【问题标题】:Implementation details of setStateVariable function in useState hookuseState hook中setStateVariable函数的实现细节
【发布时间】:2021-03-18 14:44:19
【问题描述】:

我们知道useState 是FC 中的一个钩子,它返回一个由两个元素组成的数组。第一个是状态变量,第二个是更新状态变量的函数。

const initialStateVariableValue = 0; // any primitive value
const [StateVariable, setStateVariable] = useState(initialStateVariableValue);

这里我想知道setStateVariable函数的实现细节是什么?它是如何更新状态变量的?

【问题讨论】:

标签: reactjs use-state


【解决方案1】:

如果您检查React github 上的实现,您会注意到useState 只是使用基本reducer 调用useReducer

export function useState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
  return useReducer(
    basicStateReducer,
    (initialState: any),
  );
}

所以寻找useReducer 实现,我们看到setter 函数是dispatch 函数,它根据我们当前所处的生命周期而变化

export function useReducer<S, I, A>(
  reducer: (S, A) => S,
  initialArg: I,
  init?: I => S,
): [S, Dispatch<A>] {
  ...
    // dispatch depends on lifecycle
    return [..., dispatch];
  }
}

您可以看到完整的useReducer 实现here

对于详细的实现,你应该尝试Build your own React,这最终会导致这个钩子的简化版本:

function useState(initial) {
  const oldHook =
    wipFiber.alternate &&
    wipFiber.alternate.hooks &&
    wipFiber.alternate.hooks[hookIndex];
  const hook = {
    state: oldHook ? oldHook.state : initial,
    queue: []
  };

  const actions = oldHook ? oldHook.queue : [];
  actions.forEach(action => {
    hook.state = action(hook.state);
  });

  const setState = action => {
    hook.queue.push(action);
    wipRoot = {
      dom: currentRoot.dom,
      props: currentRoot.props,
      alternate: currentRoot
    };
    nextUnitOfWork = wipRoot;
    deletions = [];
  };

  wipFiber.hooks.push(hook);
  hookIndex++;
  return [hook.state, setState];
}

简单来说:每个钩子都保存在“React钩子数组”中(这就是为什么调用顺序是必不可少的,因为钩子保存在数组的索引中 - 请参阅钩子规则),并且根据钩子的索引,每当调用它时都会改变与当前组件关联的状态对象。

【讨论】:

  • 所以 setState 是一个调度动作,但我仍然没有得到那个调度动作的实际实现。你能帮我解决这个问题吗?
  • 实际实现其实就是看源码,你期待什么答案?
猜你喜欢
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多