useState 解析
useState 使用
通常我们这样来使用 useState 方法,
function App() {
const [num, setNum] = useState(0);
const add = () => {
setNum(num + 1);
};
return (
<div>
<p>数字: {
num}</p>
<button onClick={
add}> +1 </button>
</div>
);
}
useState 的使用过程,我们先模拟一个大概的函数
function useState(initialValue) {
var value = initialValue
function setState(newVal) {
value = newVal
}
return [value, setState]
}
这个代码有一个问题,在执行 useState 的时候每次都会 var _val = initialValue,初始化数据;
于是我们可以用闭包的形式来保存状态。
const MyReact = (function() {
// 定义一个 value 保存在该模块的全局中
let value
return {
useState(initialValue) {
value = value || initialValue
function setState(newVal) {
value = newVal
}
return [value, setState]
}
}
})()
这样在每次执行的时候,就能够通过闭包的形式 来保存 value。
不过这个还是不符合 react 中的 useState。因为在实际操作中会出现多次调用,如下。
function App() {
const [name, setName] = useState('Kevin');
const [age, setAge] = useState(0);
const handleName = () => {
setNum('Dom');
};
const handleAge = () => {
setAge(age + 1);
};
return (
<div>
<p>姓名: {
name}</p>
<button onClick={
handleName}> 改名字 </button>
<p>年龄: {
age}</p>
<button onClick={
handleAge}> 加一岁 </button>
</div>
);
}
因此我们需要在改变 useState 储存状态的方式
useState 模拟实现
const MyReact = (function() {
// 开辟一个储存 hooks 的空间
let hooks = [];
// 指针从 0 开始
let currentHook = 0
return {
// 伪代码 解释重新渲染的时候 会初始化 currentHook
render(Component) {
const Comp = Component()
Comp.render()
currentHook = 0 // 重新渲染时候改变 hooks 指针
return Comp
},
useState(initialValue) {
hooks[currentHook] = hooks[currentHook] || initialValue
const setStateHookIndex = currentHook
// 这里我们暂且默认 setState 方式第一个参数不传 函数,直接传状态
const setState = newState => (hooks[setStateHookIndex] = newState)
return [hooks[currentHook++], setState]
}
}
})()
因此当重新渲染 App 的时候,再次执行 useState 的时候传入的参数 kevin , 0 也就不会去使用,而是直接拿之前 hooks 存储好的值。
hooks 规则
官网 hoos 规则中明确的提出 hooks 不要再循环,条件或嵌套函数中使用。
为什么不可以?
我们来看下
下面这样一段代码。执行 useState 重新渲染,和初始化渲染 顺序不一样就会出现如下问题
如果了解了上面 useState 模拟写法的存储方式,那么这个问题的原因就迎刃而解了。
相关参考视频讲解:进入学习
useEffect 解析
useEffect 使用
初始化会 打印一次 ‘useEffect_execute’, 改变年龄重新render,会再打印, 改变名字重新 render, 不会打印。因为依赖数组里面就监听了 age 的值
import React, {
useState, useEffect } from 'react';
function App