Shyno
Don't be shy,no problem!

hooks和函数组件

     什么是hooks?有些人认为用useState之类的函数组件是hooks,也就是说他们认为hooks是优化的函数组件.可实际上,hooks是新功能,其出现是为了完善函数组件的.useState是hook,useRef是hook.也就是说hooks是这些你在函数组件中使用的功能点,而不是组件本身.

 

useState基本使用

   官网给的例子是这样的

import React, { useState } from 'react';

function Example() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useState使用规则

1.不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们
2.只在 React 函数中调用 Hook

   第二条很好理解,毕竟是react的功能点而且是为了完善函数组件的,所以是围绕着react函数组件开发的.那第一条呢?为了理解它,我们简单理解一下useState的原理.

 

useState基本原理

   关键是三个部分:

   1.state存在哪里?

     react中虚拟dom----workInProgress树有一个memoizedState属性,这个属性是用来存放hooks相关信息的,也就是说state是存在虚拟dom里面的.

    2.state是怎么存的?

    hooks信息是一个对象.这个对象里除了本身的值和更新函数外,还需要记录一些其他的信息,比如下一次的useState更新指向的hook信息等.那假如一个函数组件中有多个useState怎么办?hooks采用了数组存放的形式,也就算是在同一个组件中,所有的hook对象是存       在一个数组中的.如:

 _hook :[
        {value:1,uplate:function1,next:hook1},
        {value:2,uplate:function2,next:hook2}
]
 

   3.state的更新是怎么更新页面的?

    useState更新时,会依次去执行hook对象数组里面的更新函数,从而修改虚拟dom,然后在完成一次组件更新后,会把当前workInProgress树赋值给current树,current会在commit阶段替换成真实的Dom树。

 

  我们再回头解释一下hooks使用的规则1,为什么hooks只能在顶层调用?

  diff算法会根据前后的虚拟dom去更新,useState也存在这个现象.也就是说,useState会根据前后的虚拟dom去更新,而hook信息是存在虚拟dom里面的,即,会存在前后两个hook对象数组.而数据的对比更新是按照下标来的.所以,假如前后的数组长度不一样,就 会导致更新混乱,即useState的使用必须是明确而且不变的.假如

if(a>0){
  const [state,setState] =useState()
}

const [state1,setState1]=useState()

这种结果会出现什么现象?a大于0和小于0的时候hooks数组长度和顺序是不一致的

a>0

 _hook :[
        {value:1,uplate:function1,next:hook1},
        {value:2,uplate:function2,next:hook2}
]
 

a<=0

 _hook :[
        {value:2,uplate:function2,next:hook2}
]
 

,当我a<=0时,更新state1会拿到value:1的值,因为a<=0时,state1的索引是0,而0对应旧hook数组里的value:1,而不是它原本应该在的value:2.

总结一下原因就是,hooks信息是存在数组里的,而每次更新都是根据索引更新的,因此,usestate的使用必须是明确的,保证hooks数组的元素数量是一致的.

     

 

posted on 2022-07-22 16:10  Shyno  阅读(1047)  评论(0编辑  收藏  举报