Mini版实现
1import React from "react";2import ReactDOM from "react-dom";34function Counter() {5 var [count, setCount] = useState(0);6 var [name, setName] = useState("john");7 const onClick = () => {8 setCount(count + 1);9 };10 const onClickName = () => {11 setName("name" + Math.random());12 };13 return (14 <div>15 <div>{count}</div>16 <button onClick={onClick}>点击</button>17 <div>{name}</div>18 <button onClick={onClickName}>点击</button>19 </div>20 );21}2223let stateArray = [];24let cursor = 0;2526function useState(initialState) {27 const currentCursor = cursor;28 stateArray[currentCursor] = stateArray[currentCursor] || initialState;29 function setState(newState) {30 stateArray[currentCursor] = newState;31 render();32 }33 ++cursor;34 return [stateArray[currentCursor], setState];35}3637export function render() {38 ReactDOM.render(39 <React.StrictMode>40 <Counter />41 </React.StrictMode>,42 document.getElementById("root")43 );44 cursor = 0;45}46render();
真实的 react useState 比这个复杂的多
mini版每次都要重新生成RootFiber,并且要重置状态’指针‘
mini版把状态存在了全局作用域,react 真实的实现是挂在 fiber 节点上的 memoizedState,
mini版本的状态指针“cursor”是个数组的索引,而真实的是通过链表实现的,
mini 版的实现只能当做一种启发
进阶版实现
尽可能的模拟内部实现
1import React from "react";2import ReactDOM from "react-dom";34let workInProgressHook;//当前工作中的hook5let isMount = true;//是否时mount时67const fiber = {//fiber节点8 memoizedState: null,//hook链表9 stateNode: App//dom10};1112const Dispatcher = (() => {//Dispatcher对象13 function mountWorkInProgressHook() {//mount时调用14 const hook = {//构建hook15 queue: {//更新队列16 pending: null//未执行的update队列17 },18 memoizedState: null,//当前state19 next: null//下一个hook20 };21 if (!fiber.memoizedState) {22 fiber.memoizedState = hook;//第一个hook的话直接赋值给fiber.memoizedState23 } else {24 workInProgressHook.next = hook;//不是第一个的话就加在上一个hook的后面,形成链表25 }26 workInProgressHook = hook;//记录当前工作的hook27 return workInProgressHook;28 }29 function updateWorkInProgressHook() {//update时调用30 let curHook = workInProgressHook;31 workInProgressHook = workInProgressHook.next;//下一个hook32 return curHook;33 }34 function useState(initialState) {35 let hook;36 if (isMount) {37 hook = mountWorkInProgressHook();38 hook.memoizedState = initialState;//初始状态39 } else {40 hook = updateWorkInProgressHook();41 }4243 let baseState = hook.memoizedState;//初始状态44 if (hook.queue.pending) {45 let firstUpdate = hook.queue.pending.next;//第一个update4647 do {48 const action = firstUpdate.action;49 baseState = action(baseState);50 firstUpdate = firstUpdate.next;//循环update链表51 } while (firstUpdate !== hook.queue.pending);//通过update的action计算state5253 hook.queue.pending = null;//重置update链表54 }55 hook.memoizedState = baseState;//赋值新的state5657 return [baseState, dispatchAction.bind(null, hook.queue)];//useState的返回58 }5960 return {61 useState62 };63})();6465function dispatchAction(queue, action) {//触发更新66 const update = {//构建update67 action,68 next: null69 };70 if (queue.pending === null) {71 update.next = update;//update的环状链表72 } else {73 update.next = queue.pending.next;//新的update的next指向前一个update74 queue.pending.next = update;//前一个update的next指向新的update75 }76 queue.pending = update;//更新queue.pending7778 isMount = false;//标志mount结束79 workInProgressHook = fiber.memoizedState;//更新workInProgressHook80 schedule();//调度更新81}8283function App() {84 let [count, setCount] = Dispatcher.useState(1);85 let [age, setAge] = Dispatcher.useState(10);86 return (87 <>88 <p>Clicked {count} times</p>89 <button onClick={() => setCount(() => count + 1)}> Add count</button>90 <p>Age is {age}</p>91 <button onClick={() => setAge(() => age + 1)}> Add age</button>92 </>93 );94}9596function schedule() {97 ReactDOM.render(<App />, document.querySelector("#root"));98}99100schedule();