React Hook 原理,及如何使用Hook

一、 Hook使用规则 

  • 只在最顶层使用Hook

  • 不要在循环,条件或嵌套函数中调用Hook;

  • 只在组件函数和自定义hook中调用Hook

Q1 : 为什么 hook 不能 在循环,条件或嵌套函数中调用Hook ? 

 A1:  因为这跟React的渲染函数和React Hook的实现原理有关,如果在循环,条件或嵌套函数中调用hook,会影响到了React自身记录的Hook顺序,会导致组件状态(值)不一致问题。

Q2: 为什么组件内,刷新了一次后,useState 仍然能保持最新的值,而不是回到初始值? 

A2:  这是因为,useState 这个hook底层逻辑是利用闭包原理,它会把最新的值,初始化的值,下一个要调用的hook这些值创建成一个fiber对象,后面每次刷新都会从这个fiber对象上获取。

     

二、 简单实现一个 useState 

demo1 : 问题在每次刷新,值都是初始化

function useState(initialValue) {
  var state = initialValue;
  function setState(newState) {
    state = newState;
    render();
  }
  return [state, setState];
}

demo2 :  问题在,如果组件内使用多个useState, _state 值会被覆盖

var _state; // 把 state 存储在外面

function useState(initialValue) {
  _state = _state || initialValue; // 如果没有 _state,说明是第一次执行,把 initialValue 复制给它
  function setState(newState) {
    _state = newState;
    render();
  }
  return [_state, setState];
}

demo3:    按照hook的顺序,把state值依次存进  memoizedState  中 。

这就是为什么  hook 不能 在循环,条件或嵌套函数中调用Hook , 因为这样会影响React自身记录的Hook顺序。

let memoizedState = []; // hooks 存放在这个数组
let cursor = 0; // 当前 memoizedState 下标

function useState(initialValue) {
  memoizedState[cursor] = memoizedState[cursor] || initialValue;
  const currentCursor = cursor;
  function setState(newState) {
    memoizedState[currentCursor] = newState;
    render();
  }
  return [memoizedState[cursor++], setState]; // 返回当前 state,并把 cursor 加 1
}

三、 真正实现一个 useState 

虽然我们用数组基本实现了一个可用的 Hooks,了解了 Hooks 的原理,但在 React 中,实现方式却有一些差异的。

  • React 中是通过类似单链表的形式来代替数组的。通过 next 按顺序串联所有的 hook。

    type Hooks = {
    	memoizedState: any, // 指向当前渲染节点 Fiber
      baseState: any, // 初始化 initialState, 已经每次 dispatch 之后 newState
      baseUpdate: Update | null,// 当前需要更新的 Update ,每次更新完之后,会赋值上一个 update,方便 react 在渲染错误的边缘,数据回溯
      queue: UpdateQueue | null,// UpdateQueue 通过
      next: Hook | null, // link 到下一个 hooks,通过 next 串联每一 hooks
    }
     
    type Effect = {
      tag: HookEffectTag, // effectTag 标记当前 hook 作用在 life-cycles 的哪一个阶段
      create: () => mixed, // 初始化 callback
      destroy: (() => mixed) | null, // 卸载 callback
      deps: Array | null,
      next: Effect, // 同上 
    };

  • memoizedState,cursor 是存在哪里的?如何和每个函数组件一一对应的?

    我们知道,react 会生成一棵组件树(或Fiber 单链表),树中每个节点对应了一个组件,hooks 的数据就作为组件的一个信息,存储在这些节点上,伴随组件一起出生,一起死亡。

React Hook 原理,及如何使用Hook_第1张图片

参考: 

【React全解3】React.useState原理详解,一次性搞懂useState_react usestate-CSDN博客

React Hooks 原理 · Issue #26 · brickspert/blog · GitHub

你可能感兴趣的:(react.js,前端,前端框架)