0-7【React】Hooks 原理解析(useState、useRef、useContext)
1.useState
- 流程:
1.首次渲染会执行函数组件App(),也就是函数会执行一次,useState(0)也会执行,打印出 n=0
2.当点击按钮调用 setN({n:n+1}) 改变n的值时,函数组件App()会再次被调用,重新渲染,打印出 n=1 - 执行setN的时候:n会变吗?App()会重新执行吗?
1.n不会变,setN不会改变n,它只是把传入的新值存起来,方便后面useState去取新值
2.App()会重新执行,但每次执行 useState(0) 的时候,n每次的值是不同的 - useState
useState肯定会从 setN 存入新值的地方取出新值 - 存储位置
每个组件都有自己的数据存储仓库,我们将其命名为 state
注意:旧n和新n同时存在
这就是React的思想,永远产生新的对象,不改变旧值
1.1 分析
- setN
1.setN 一定会修改数据 x,将 n+1 存入 x
2.setN 一定会触发<App />
重新渲染(re-render) - useState
useState 肯定会从 x 读取 n 的最新值 - x
每个组件都有自己的数据 x,我们将其命名为 _state - useState 重新执行不重置 0 的原理
就是将函数内部变量的 _state 声明在 hook 外面作为全局变量,这样就不会每次调用 hook 都重置
//全局变量
let _state
//API内部
const myUseState = initialValue =>{
//判断初始值是否存在,存在就是自己的值,不存在就赋初始值
_state = _state === undefined ? initialValue : _state
}
myUseState(0)
1.2 多个useState兼容
- 如果一个组件用了两次useState,那么一个全局变量 _state就无法满足
- 将_state设置为数组
如:_state=[0,0] - 每useState一次,就把变量push到数组中
知道每个变量对应的数组下标即可对其进行操作,顺序很重要
1.3 _state 数组方案的缺点
- useState 调用顺序很重要
1.若第一次渲染时 n 是第一个,m第二,k第三
2.第二次渲染则必须保证循序完全一致 - React不允许出现以下代码
如果 m 后面还有 k,那么当m不满足条件时不执行时,后面 k 执行,k就取了_state中m的值
1.4 虚拟DOM
- 组件App用了_state和index,其他组件用什么?
答:给每个组件创建一个_state和index - 放在全局作用域重名怎么办?
答:放在组件对应的虚拟节点对象上 - 每个组件都有一个对应的虚拟DOM,虚拟DOM上面都有自己的 _state 和 index
- React会维护一个虚拟的 DOM 树
1.5 总结
- 每个函数组件对应一个 React 节点
- 每个节点保存着 state 和 index
- useState 会读取 state[index]
- index 有 useState 出现的顺序决定
- setState 会修改 state,并触发更新
- 始终记住
1.setN不会改变n,而是产生新的数据
2.如果不希望出现新的n:可以使用 useRef 或 useContext 等
2.useRef
- useRef不仅可以用于引用 div,还能用于任意数据
- 每次 setN 都会产生一个新的n
- 采用useRef
优点:从始至终只有一个n,且可以直接对n操作
缺点:n改变,不会自动渲染页面,只能手动更新 - React中没有能手动更新的API,可以自己造一个
//创建
const nRef = React.useRef(0) //{current:0}
//使用
return (
<div>
{nRef.current}
<button onClick={()=>{nRef.current+1}}>+1</button>
</div>
)
3.useContext
- useContext:上下文,也就等同于全局变量
不过是局部的全局变量 - useContext不仅能贯穿始终,还能贯穿不同组件
- 范围内的组件都可以使用state
常用于切换主题