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
    常用于切换主题