React Hooks principle

Original Address
React Hooks examples of teaching

Currently, Hooks should be React the hottest concepts, and before reading this article, I hope you understand the basic usage of Hooks.

When using Hooks, we may have a lot of doubts

  1. Why do only the outermost Hook function call, do not judge or subroutine in a loop, a conditional call?
  2. Why useEffect second argument is an empty array, the equivalent of ComponentDidMount, only once?
  3. How to Hook a custom function that affect the use of its components?
  4. How to Capture Value property is generated?
  5. ......

In this article we will not explain Hooks concepts and usage, but will take you from zero to achieve a tiny hooks, know these know why.

useState

  1. The easiest useState usage is this:
    demo1: https://codesandbox.io/s/v0nqm309q3

    function Counter() {
      var [count, setCount] = useState(0);
    
      return (
        <div>
          <div>{count}</div>
          <Button onClick={() => { setCount(count + 1); }}>
            点击
          </Button>
        </div>
      );
    }
    
  2. Based on usage useState, we try to achieve own a useState:
    demo2: https://codesandbox.io/s/myy5qvoxpp

    function useState(initialValue) {
      var state = initialValue;
      function setState(newState) {
        state = newState;
        render();
      }
      return [state, setState];
    }
    
  3. Then we found, click on Button's time, count and will not change, why? We do not store state, each component rendering Counter time, state is a new reset.

    Naturally we can think of, the state extracted, exist outside useState.
    Demo3: https://codesandbox.io/s/q9wq6w5k3w

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

So far, we have achieved a useState can work, at least for now nothing issue.
Next, let's look at how to achieve useEffect.

useEffect

useEffect is another basic Hook, for treatment of side effects, the most simple usage is this:
demo4: https://codesandbox.io/s/93jp55qyp4

 useEffect(() => {
    console.log(count);
 }, [count]);

We know useEffect have the following characteristics:

  1. There are two parameters callback and an array of dependencies
  2. If no dependencies exist, then the callback will be executed every time render
  3. If dependencies exist only if it has changed, callback will be performed

Let's achieve a useEffect
demo5: https://codesandbox.io/s/3kv3zlvzl1

let _deps; // _deps 记录 useEffect 上一次的 依赖

function useEffect(callback, depArray) {
  const hasNoDeps = !depArray; // 如果 dependencies 不存在
  const hasChangedDeps = _deps
    ? !depArray.every((el, i) => el === _deps[i]) // 两次的 dependencies 是否完全相等
    : true;
  /* 如果 dependencies 不存在,或者 dependencies 有变化*/
  if (hasNoDeps || hasChangedDeps) {
    callback();
    _deps = depArray;
  }
}

Here, we can achieve a useEffect a job, it does not seem so difficult.
At this point we should be able to answer a question:

Q: Why does the second argument is an empty array, the equivalent componentDidMount?

A: Because the dependent has not changed, callback will not execute the second.

Not Magic, just Arrays

Until now, we have achieved useState and useEffect can work. But there is a big problem: Talia can be used only once, because there is only one _state and a _deps. such as

const [count, setCount] = useState(0);
const [username, setUsername] = useState('fan');

count and username will always be equal, because they share a _state, and no place to store two values. We need to store multiple _state and _deps.

Such as " React Hooks: not Magic, the Just Arrays " written, we can use an array to solve the problem Hooks reuse.
demo6: https://codesandbox.io/s/50ww35vkzl

The key is the code:

  1. First when rendering, in order useState, useEffect of the state, deps like stuffed memoizedState array sequentially.
  2. Update, in order, from the value of the last recorded memoizedState is out.
  3. If you still do not know, you can see the following chart.
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
}

function useEffect(callback, depArray) {
  const hasNoDeps = !depArray;
  const deps = memoizedState[cursor];
  const hasChangedDeps = deps
    ? !depArray.every((el, i) => el === deps[i])
    : true;
  if (hasNoDeps || hasChangedDeps) {
    callback();
    memoizedState[cursor] = depArray;
  }
  cursor++;
}

We use diagrams to describe the process of memoizedState and the cursor changes.

1. Initialization

3963958-e00c1d5401eae31e.png
1

2. The initial rendering

3963958-b5a02bdecc22fc06.png
2

3. Event Trigger

3963958-218c9978f0d92f54.png
3

4. Re Render

3963958-d693eb27d92eb3e1.png
4

Here, we can achieve an arbitrary useState and useEffect reuse.

Also, you can answer a few questions:

Q: Why do only the outermost call Hook in function? Why Do not judge or subroutine call in the cycle conditions.

A: memoizedState array is defined in order to place the hook data, if the sequence variation hook, memoizedState not perceived.

Q: How customizable Hook affect its function components?

A: share the same memoizedState, share the same sequence.

Q: "Capture Value" characteristic is how to generate?

A: Every time ReRender time, are re-assembly to perform a function, a function of the components has been performed before and will not do anything.

React to achieve real

Although we basically achieved by an array of available Hooks, Hooks understand the principle, but React in implementation there are some differences.

  • React is instead in the form of an array similar to a single list. Next in order in series through all of the hook.

    type Hooks = {
        memoizedState: any, // 指向当前渲染节点 Fiber
      baseState: any, // 初始化 initialState, 已经每次 dispatch 之后 newState
      baseUpdate: Update<any> | null,// 当前需要更新的 Update ,每次更新完之后,会赋值上一个 update,方便 react 在渲染错误的边缘,数据回溯
      queue: UpdateQueue<any> | 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<mixed> | null,
      next: Effect, // 同上 
    };
    
  • memoizedState, cursor is where exist? And how each function components one to one?

    We know, react will generate a component tree (or Fiber singly linked list), each tree node corresponds to a component, hooks on the data as a component of the information stored on these nodes, along with the components of birth, death together .

3963958-cb624fde9f2570cd.png
5

More reading: React Hook thorough system of principles

Guess you like

Origin blog.csdn.net/weixin_34014277/article/details/90892770
Recommended