Skip to main content

React Hooks Polyfills

useState

  const useMyState = (initialValue) => {
const hookIdTrackerRef = React.useRef(0); // Component-specific tracker
const statesRef = React.useRef([]); // Component-specific state storage

const localHookId = hookIdTrackerRef.current++; // Assign unique ID for this hook

// Initialize state lazily
if (statesRef.current[localHookId] === undefined) {
statesRef.current[localHookId] =
typeof initialValue === "function" ? initialValue() : initialValue;
}

const currentState = statesRef.current[localHookId]; // Get the current state

const [, rerender] = useReducer(() => ({}), {}); // Trigger re-render

const setValue = (newValue) => {
// If newValue is a function, compute based on the current state
if (typeof newValue === "function") {
newValue = newValue(statesRef.current[localHookId]);
}

// Check for state change
const isValueChanged = !Object.is(newValue, statesRef.current[localHookId]);
if (isValueChanged) {
statesRef.current[localHookId] = newValue; // Update state
hookIdTrackerRef.current = 0;
rerender({}); // Trigger re-render
}
};

return [currentState, setValue];
};

useEffect

  const myEffect = (callback, depsArray) => {
const firstRenderRef = React.useRef(true); // Tracks if it's the first render
const prevDepsRef = React.useRef([]); // Stores the previous dependencies
const cleanupRef = React.useRef(null); // Stores the cleanup function

// Handle first render
if (firstRenderRef.current) {
firstRenderRef.current = false;
cleanupRef.current = callback(); // Call effect
prevDepsRef.current = depsArray ?? []; // Store dependencies
return;
}

// Check if dependencies have changed
const haveDepsChanged =
!depsArray ||
depsArray.some((dep, i) => !Object.is(dep, prevDepsRef.current[i]));

// Cleanup and invoke callback if dependencies changed
if (haveDepsChanged) {
if (typeof cleanupRef.current === "function") {
cleanupRef.current(); // Call cleanup
}
cleanupRef.current = callback(); // Call effect
}

prevDepsRef.current = depsArray || []; // Update dependencies
};

useMemo

function useMemo(factory, deps) {
const ref = React.useRef({ deps: undefined, value: undefined })

function areEqual(oldDeps, newDeps) {
if (!oldDeps || oldDeps.length !== newDeps.length) return false
return oldDeps.every((dep, i) => Object.is(dep, newDeps[i]))
}

if (!areEqual(ref.current.deps, deps)) {
ref.current.value = factory()
ref.current.deps = deps
}

return ref.current.value
}

useCallback

import * as React from 'react'

function useCallback(callback, deps) {
const ref = React.useRef({ deps: undefined, memoizedCallback: null });

function areDepsEqual(oldDeps, newDeps) {
if (!oldDeps || oldDeps.length !== newDeps.length) return false;
return oldDeps.every((dep, i) => Object.is(dep, newDeps[i]));
}

if (!areDepsEqual(ref.current.deps, deps)) {
ref.current.memoizedCallback = callback;
ref.current.deps = deps;
}

return ref.current.memoizedCallback;
}

React.memo

function memo(Component, areEqual) {
class MemoizedComponent extends React.Component {
static displayName = `Memo(${
Component.displayName || Component.name || "Component"
})`;

shouldComponentUpdate(nextProps) {
if (areEqual) {
return !areEqual(this.props, nextProps);
}

// When no areEqual is provided, do a shallow props comparison
const prevProps = this.props;
if (Object.keys(prevProps).length !== Object.keys(nextProps).length) {
return true;
}
for (const key in nextProps) {
if (prevProps[key] !== nextProps[key]) {
return true;
}
}
return false;
}

render() {
return React.createElement(Component, this.props);
}
}

return Object.assign(MemoizedComponent, Component);
}