React Renderers: an Overview
One of the most advanced features of React is the ability to write renderers for different environments. You can be surprised, but it’s possible to create CLI or Hardware apps using React! In this article, I will look over the most interesting React renderers.
Ink
Ink is a React for CLIs. It allows you to build and test your CLI output using components:
The code of the demo:
const Counter = () => {
const [i, setI] = useState(0);
useEffect(() => {
setInterval(() => {
setI(prev => prev + 1);
}, 100);
}, []);
return <Color>
{i} tests passed
</Color>;
}
Ink used by popular libraries such a Gatsby, Parcel, Yarn 2, etc. Also, there are similar libraries such a react-blessed.
React Hardware
React Hardware allows to operate some hardware devices (such as Arduino) through React components:
The code of the demo:
const App = () => {
const [ledState, setLedState] = useState(false);
useEffect(() => {
setInterval(() => {
setLedState(prev => !prev);
}, 1000);
}, []);
return <Led pin={13} value={ledState ? 255 : 0} />
}
const PORT = 'dev/tty.usbmodem1411';
ReactHardware.render(<App />, PORT);
React Figma
React Figma is a React renderer into Figma. It allows you to use React components as a source for your designs.
React Figma can be useful for describing design systems, creating automations or integrations between some APIs and Figma. E.g. OpenAI and react-jsx-parser allows to create amazing concepts like this. There is sample code written on react-figma:
import * as React from 'react';
import { Page, View, Text } from 'react-figma';
export const App = () => {
return (
<Page name="New page" isCurrent>
<View>
<View style={{ width: 200, height: 100, backgroundColor: '#dd55aa' }} />
<Text style={{ color: '#ffffff' }}>text</Text>
</View>
</Page>
);
};
Figma is the most popular design tool for now, but other editors have similar renderers: react-sketchapp for Sketch, react-xd for Adobe XD.
react-three-fiber
react-three-fiber is a React renderer for threejs on the web and react-native.
There is a sample code:
import ReactDOM from 'react-dom'
import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from 'react-three-fiber'
function Box(props) {
// This reference will give us direct access to the mesh
const mesh = useRef()
// Set up state for the hovered and active state
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
// Rotate mesh every frame, this is outside of React without overhead
useFrame(() => (mesh.current.rotation.x = mesh.current.rotation.y += 0.01))
return (
<mesh
{...props}
ref={mesh}
scale={active ? [1.5, 1.5, 1.5] : [1, 1, 1]}
onClick={(e) => setActive(!active)}
onPointerOver={(e) => setHover(true)}
onPointerOut={(e) => setHover(false)}>
<boxBufferGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
ReactDOM.render(
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>,
document.getElementById('root')
)
Building dynamic scene graphs declaratively with re-usable components makes dealing with threejs easier and brings order and sanity to your codebase. These components react to state changes, are interactive out of the box, and can tap into React’s infinite ecosystem.
The library has an amazing ecosystem with packages such as react-three-flex - it’s a flexbox implementation, react-xr, react-postprocessing and many others.
react-nil
react-nil is a custom react renderer that renders nothing.
import React, { useState, useEffect } from "react"
import { render } from "react-nil"
function Foo() {
const [active, set] = useState(false)
useEffect(() => void setInterval(() => set((a) => !a), 1000), [])
console.log(active)
// This is a logical component without a view, it renders nothing,
// but it has a real lifecycle and is managed by React regardless.
return null
}
render(<Foo />)
This package allows you to bring Reacts high-level component abstraction to Node, or wherever you need it. Why not manage your REST endpoints like routes on the client, users as components with mount/unmount lifecycles, self-contained separation of concern, and clean side-effects. Suspense for requests, etc.
react-docx
react-docx is a brand new React reconciler for DOCX.js. A sample code:
renderAsyncDocument(
<section>
<paragraph heading={Docx.HeadingLevel.HEADING_1}>
You can pass props as if you are passing them to constructor
</paragraph>
<p>There are some helpful shortcuts for often used tags, like this</p>
<p>
<t>this one is for TextRun</t>
</p>
<p>
<img
src="base64 string or buffer object works"
width={200}
height={200}
/>
<href
src="http://localhost:8080"
label={"For images and links shortcuts object are provided"}
/>
This allows for removal of boilerplate for often used objects. In future
more such object will be implemented.
</p>
<Component text="You can use componets of course, just like in react!">
<t>A child</t>
</Component>
</section>
).then((document) => console.log("This is rendered docx document", document));
Also, react-pdf and redocx can be used for equal needs.
Conclusion
Hope you get inspired for creating your own React renderer, it’s possible due to React Reconciler package. I didn’t mention the most popular renderers such as react-dom or react-native, but I tried to collect the most unusual of them. Are you have any additions? Propose them on the comments! 🙌
Thanks
- Yaroslav Losev @losyear - fact checking, editing
Links
Rendrers:
Renderers writing:
- React Reconciler package
- Atul R – Beginners guide to Custom React Renderers
- Manas Jayanth – Learn how React Reconciler package works by building your own lightweight React DOM
- Sophie Alpert – Building a Custom React Renderer
- Aziz Khambati – Building an Async React Renderer with Diffing in Web Worker
Top comments (1)
Jack of all trade