Mastering React Advanced Hooks with TypeScript: Simulating a Dynamic Equation System
Mastering React Advanced Hooks with TypeScript: Simulating a Dynamic Equation System In today’s React applications, advanced hooks like useContext, useReducer, and useLayoutEffect provide powerful tools to manage state, coordinate rendering, and share data efficiently—without introducing excessive boilerplate. In this article, we’ll implement these hooks in a real-world mathematical scenario: simulating a system of equations with shared coefficients and synchronized updates using React + TypeScript. Objective: Simulate and Manage Dynamic Equations We’ll create a dynamic environment with: Global equation context using useContext State transitions and actions using useReducer Layout synchronization using useLayoutEffect to ensure DOM alignment before render Hook Overview in this Context Hook Purpose useContext Share coefficients across components useReducer Manage complex state transitions like equation switching useLayoutEffect Ensure the canvas and equation list align correctly before paint Step 1: Define Global Math Context // MathContext.tsx import React, { createContext, useReducer, useContext } from "react"; type Equation = { id: string; formula: string; coefficients: number[]; }; type State = { activeEquation: Equation; }; type Action = | { type: "SET_EQUATION"; payload: Equation }; const initialState: State = { activeEquation: { id: "eq1", formula: "y = ax² + bx + c", coefficients: [1, 2, 1] } }; const MathContext = createContext(undefined); function mathReducer(state: State, action: Action): State { switch (action.type) { case "SET_EQUATION": return { ...state, activeEquation: action.payload }; default: return state; } } export const MathProvider: React.FC = ({ children }) => { const [state, dispatch] = useReducer(mathReducer, initialState); return ( {children} ); }; export const useMath = () => { const context = useContext(MathContext); if (!context) throw new Error("useMath must be used within MathProvider"); return context; }; Step 2: Visualizing the Equation import { useLayoutEffect, useRef } from "react"; import { useMath } from "./MathContext"; export const EquationVisualizer = () => { const canvasRef = useRef(null); const { state } = useMath(); const [a, b, c] = state.activeEquation.coefficients; useLayoutEffect(() => { const canvas = canvasRef.current; const ctx = canvas?.getContext("2d"); if (!canvas || !ctx) return; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); for (let x = -100; x ; }; Step 3: Dynamic Equation Switching const EquationSelector = () => { const { dispatch } = useMath(); const handleChange = () => { dispatch({ type: "SET_EQUATION", payload: { id: "eq2", formula: "y = 2x² - 3x + 5", coefficients: [2, -3, 5] } }); }; return Switch Equation; }; App Component import { MathProvider } from "./MathContext"; import { EquationVisualizer } from "./EquationVisualizer"; import { EquationSelector } from "./EquationSelector"; export const App = () => (

Mastering React Advanced Hooks with TypeScript: Simulating a Dynamic Equation System
In today’s React applications, advanced hooks like useContext
, useReducer
, and useLayoutEffect
provide powerful tools to manage state, coordinate rendering, and share data efficiently—without introducing excessive boilerplate.
In this article, we’ll implement these hooks in a real-world mathematical scenario: simulating a system of equations with shared coefficients and synchronized updates using React + TypeScript
.
Objective: Simulate and Manage Dynamic Equations
We’ll create a dynamic environment with:
- Global equation context using
useContext
- State transitions and actions using
useReducer
- Layout synchronization using
useLayoutEffect
to ensure DOM alignment before render
Hook Overview in this Context
Hook | Purpose |
---|---|
useContext |
Share coefficients across components |
useReducer |
Manage complex state transitions like equation switching |
useLayoutEffect |
Ensure the canvas and equation list align correctly before paint |
Step 1: Define Global Math Context
// MathContext.tsx
import React, { createContext, useReducer, useContext } from "react";
type Equation = {
id: string;
formula: string;
coefficients: number[];
};
type State = {
activeEquation: Equation;
};
type Action =
| { type: "SET_EQUATION"; payload: Equation };
const initialState: State = {
activeEquation: {
id: "eq1",
formula: "y = ax² + bx + c",
coefficients: [1, 2, 1]
}
};
const MathContext = createContext<{ state: State; dispatch: React.Dispatch<Action> } | undefined>(undefined);
function mathReducer(state: State, action: Action): State {
switch (action.type) {
case "SET_EQUATION":
return { ...state, activeEquation: action.payload };
default:
return state;
}
}
export const MathProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [state, dispatch] = useReducer(mathReducer, initialState);
return (
<MathContext.Provider value={{ state, dispatch }}>
{children}
MathContext.Provider>
);
};
export const useMath = () => {
const context = useContext(MathContext);
if (!context) throw new Error("useMath must be used within MathProvider");
return context;
};
Step 2: Visualizing the Equation
import { useLayoutEffect, useRef } from "react";
import { useMath } from "./MathContext";
export const EquationVisualizer = () => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const { state } = useMath();
const [a, b, c] = state.activeEquation.coefficients;
useLayoutEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (!canvas || !ctx) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
for (let x = -100; x <= 100; x++) {
const px = canvas.width / 2 + x;
const y = a * x * x + b * x + c;
const py = canvas.height / 2 - y;
x === -100 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
}
ctx.strokeStyle = "teal";
ctx.lineWidth = 2;
ctx.stroke();
}, [a, b, c]);
return <canvas ref={canvasRef} width={400} height={400} style={{ border: "1px solid gray" }} />;
};
Step 3: Dynamic Equation Switching
const EquationSelector = () => {
const { dispatch } = useMath();
const handleChange = () => {
dispatch({
type: "SET_EQUATION",
payload: {
id: "eq2",
formula: "y = 2x² - 3x + 5",
coefficients: [2, -3, 5]
}
});
};
return <button onClick={handleChange}>Switch Equationbutton>;
};
App Component
import { MathProvider } from "./MathContext";
import { EquationVisualizer } from "./EquationVisualizer";
import { EquationSelector } from "./EquationSelector";
export const App = () => (
<MathProvider>
<h1>