mini-react中几个hooks的实现

73 阅读2分钟

用过react的人都知道,项目中最经常使用的hooks有 useState,useEffect等,今天就来学习一下使用方式,并非简单实现一下。代码见这里

- useState:状态

useState使用方法:

let [state, setState] = React.useState(initialState);

返回一个 state,以及更新 state 的函数。 在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。

实现方式:

let stateHooks;
let stateHookIndex;
function useState(initial) {
  //
  let currentFiber = wipFiber;
  const oldHook = currentFiber.alternate?.stateHooks[stateHookIndex];
  const stateHook = {
    state: oldHook ? oldHook.state : initial,
    queue: oldHook ? oldHook.queue : [],
  };

  // 调用
  stateHook.queue.forEach((action) => {
    stateHook.state = action(stateHook.state);
  });
  stateHook.queue = [];
  stateHookIndex++;
  stateHooks.push(stateHook);

  currentFiber.stateHooks = stateHooks;
  function setState(action) {
    // stateHook.state = action(stateHook.state);
    const eagerState =
      typeof action === "function" ? action(stateHook.state) : action;
    if (eagerState == stateHook.state) return;
    stateHook.queue.push(typeof action === "function" ? action : () => action);
    wipRoot = {
      ...currentFiber,
      alternate: currentFiber,
    };
    nextWorkOfUnit = wipRoot;
  }
  return [stateHook.state, setState];
}

- useEffect:副作用,代替生命周期

该 Hook 接收一个包含命令式、且可能有副作用代码的函数。 使用方式:

 React.useEffect(()=>{
       // todo
 },[]);

在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。

使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后延迟执行。 默认情况下,effect 将在每轮渲染结束后执行,但你可以选择让它在只有某些值改变的时候才执行。

实现代码:

// 调用时机?在react完成对 dom 的渲染之后,并且浏览器完成绘制之前
let effectHooks;
function useEffect(callback, deps) {
  const effectHook = {
    callback,
    deps,
    cleanup: undefined,
  };
  effectHooks.push(effectHook);
  wipFiber.effectHooks = effectHooks;
}

不是每次改变都去更新,而是一次性收集起来,统一进行更新,这也是优化点之一,不需要频繁的变动。

- useCallback: 性能优化

待完成

不是结束,是新的开始,未来走的每一步。