模拟实现
2023年06月11日
一、实现
1.1 /packages/react/index.js
export const useCallback = (callback, deps) => {
const dispatcher = resolveDispatcher();
return dispatcher.useCallback(callback, deps);
};
1.2 /packages/react-reconciler/fiberHooks.js
function mountCallback(callback, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
hook.memoizedState = [callback, nextDeps];
return callback;
}
function updateCallback(callback, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (nextDeps !== null) {
const prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}
/**
* @description: Mount 阶段 Hooks 实现
*/
const HooksDispatcherOnMount = {
use,
useRef: mountRef,
useMemo: mountMemo,
useState: mountState,
useEffect: mountEffect,
useContext: readContext,
useCallback: mountCallback,
useTransition: mountTransition
};
/**
* @description: Update 阶段 Hooks 实现
*/
const HooksDispatcherOnUpdate = {
use,
useRef: updateRef,
useMemo: updateMemo,
useState: updateState,
useEffect: updateEffect,
useContext: readContext,
useCallback: updateCallback,
useTransition: updateTransition
};
二、测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Mini KaSong useCallback</title>
<script>
var process = {
env: {
NODE_ENV: 'development'
}
};
</script>
<script src="../dist/react.iife.js"></script>
</head>
<body>
<div id="root"></div>
<script>
const {
ReactDOM: { createRoot },
React: { memo, useState, useCallback, createElement }
} = React;
function Cpn(props) {
const { addOne } = props;
console.log('Cpn Render', props);
return createElement('div', { onClick: addOne }, 'Cpn');
}
const MemoCpn = memo(Cpn);
function App() {
const [num, setNum] = useState(0);
console.log('App Render');
// const addOne = () => {
// setNum(num + 1);
// };
const addOne = useCallback(() => {
setNum(num + 1);
}, []);
return createElement('div', {}, [createElement(MemoCpn, { addOne })]);
}
const root = createRoot(document.getElementById('root'));
root.render(createElement(App));
</script>
</body>
</html>