What is Mixed-Mode in React.js?
Mixed-Mode in React.js is a situation where an app contains components that render to the DOM and components that don’t. A basic example of a component that doesn’t render to the DOM is the Redirect component from react-router-dom. This component redirects a user to a route passed to it as a prop. It does this by calling history.push. In this way, the Redirect component does not render JSX, but rather, performs a redirection effect on mount.
import { useEffect } from 'react'import { useHistory } from 'react-router-dom'const Redirect = ({ to }) => {const history = useHistory()useEffect(() => {history.push(to)}, [])return null}export default Redirect
Renderless component canvas example
A more involved example is a declarative HTML5 canvas component. To create such a component, we’ll define a Canvas with a rectangle drawn within. Here, a canvas element, which is a non-DOM browser API, is created with a ref attached.
Graphics can only be drawn on the <canvas></canvas> element using Javascript. Graphics can be drawn in 2d and 3d through the 2d or 3d context. For us to draw a 2d rectangle, we must use the 2d context that’s returned from getContext("2d") canvas method call.
A draw function is defined below that draws a green rectangle on the 2d context. Although <canvas ref={canvasRef}></canvas> was returned from the Canvas component, it does render on the browser DOM. You can’t add event listeners to the rectangle or style it using CSS because it is non-DOM.
So, essentially, React Mixed Mode is the combination of Elements that render to the DOM and elements that don’t.
import React, { useEffect, useRef } from "react";
function Canvas() {
const canvasRef = useRef();
useEffect(() => {
const ctx = canvasRef.current.getContext("2d");
draw(ctx);
}, []);
const draw = (ctx) => {
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 150, 100);
};
return <canvas ref={canvasRef}></canvas>;
}
export default Canvas;
Declarative way of working with Renderless components in React Mixed Mode
We can abstract the Rectangle component from the Canvas component to a Rectangle component. We will define a rectangle component that receives props. These props will contain the x coordinate, y coordinate, width, and height of the canvas rectangle graphic.
To achieve this feat, we pass canvas 2d context using a global state management tool like React’s Context API so that all children rectangles can draw on the canvas without the need for prop drilling.
Prop drilling is a situation where a React parent component passes props to intermediate child components that don’t use those props. These intermediate components then pass those props to the children that need them.
import React, { useContext, useEffect } from "react";
import { CanvasContext } from "./Canvas";
function Rectangle({ color, coordinates }) {
const { ctx } = useContext(CanvasContext);
const { x, y, width, height } = coordinates;
useEffect(() => {
if (ctx) {
ctx.fillStyle = color;
ctx.fillRect(x, y, width, height);
}
}, [x, y, width, height, ctx, color]);
return null;
}
export default Rectangle;
Using React Mixed-Mode
React Mix-Mode is useful when using a Non-DOM browser API like the Canvas API in a React way. The basic principle of Mixed-Mode lies with the non-DOM components, which:
- use the Context API to receive necessary props
- use Refs to target non-DOM nodes
- use the React Lifecycle to determine when rendering occurs