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);
}