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数组的元素数量是一致的.