跳到主要内容

模拟实现

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>