跳到主要内容

模拟实现

2023年06月11日
柏拉文
越努力,越幸运

一、认识


1.1 /packages/react/index.js

export const useMemo = (nextCreate, deps) => {
const dispatcher = resolveDispatcher();
return dispatcher.useMemo(nextCreate, deps);
};

1.2 /packages/react-reconciler/fiberHooks.js

function mountMemo(nextCreate, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}

function updateMemo(nextCreate, 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];
}
}

const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}

/**
* @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 useMemo</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, useMemo, createElement }
} = React;

function Cpn(props) {
const { uuid } = props;
console.log('Cpn Render', props);

return createElement('div', {}, 'Cpn');
}

const MemoCpn = memo(Cpn);

function getUniqueIdByNanoID(size = 10) {
let id = '';
let i = size;
const urlAlphabet =
'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
while (i--) {
id += urlAlphabet[(Math.random() * 64) | 0];
}
return id;
}

function getUniqueId(size) {
return getUniqueIdByNanoID(size);
}

function App() {
const [num, setNum] = useState(0);

console.log('App Render');

const uuid = getUniqueId();
// const uuid = useMemo(() => getUniqueId(), []);

return createElement('div', { onClick: () => setNum(num + 1) }, [
createElement(MemoCpn, { uuid })
]);
}

const root = createRoot(document.getElementById('root'));
root.render(createElement(App));
</script>
</body>
</html>