一个useState学会React的主要思想
正经学徒,佛系记录,不搞事情
皮毛React开发者:一个useState有什么好学的,hook那么多,哪个不比useState难
自身React开发者:学的不是如何使用,而是为什么会这样
直接进入主题,对React文档案例进行分析,可以先给出点击按钮后numebr的值再看解释
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
console.log(number)
setNumber(number + 1);
console.log(number)
setNumber(number + 1);
console.log(number)
}}>+3</button>
</>
)
}
反正肯定不是3,是3还有什么好学的,理解这个问题首先要知道React的渲染机制,React为了能够更快的渲染,会挣对state的值的变化去渲染对应的组件,而不是整个页面重新渲染,并且会自动渲染全部相关嵌套的组件。
对于普通的JavaScript的变量 let number = 0; 即使是对number的值进行操作,也是不会重新渲染组件,这是因为React遵循两个基本原则
- 内存变量不会在每次重新渲染中保存下来
- 改变内存变量不会触发重新渲染
因此引入了useState的hook,而上面例子useState的setNumber改变会触发重新渲染。React渲染的机制是等待整个event handler完成后才会触发渲染,它有一个队列的概念,而上面的例子就是将三个 setNumber(number + 1); 加入到Queue中后在一次性渲染,要问为什么,三次计算完成后渲染一次快,还是计算三次的同时渲染三次快呢,尤其是在如果三次计算都是操作同一个值的情况,多次渲染将会是非常浪费的一个动作。
有了这些概念,再来看例子,上面例子的解释就是useState setNumber在某个event hander中并不会改变变量number的值,numebr的值只在重新渲染后生效,即,整个onClick方法执行完才会渲染number的值,因此console.log的值全都是0,而Queue里是同时执行了三次setNumber(0 + 1);,最终的结果是 1
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
}}>+3</button>
</>
)
}
这一个例子的关键点在于 n => n+1,这意味着每次setNumber的 n 都是用上一次的值,结果是3
queued update | n | returns |
---|---|---|
n => n + 1 | 0 | 0 + 1 = 1 |
n => n + 1 | 1 | 1 + 1 = 2 |
n => n + 1 | 2 | 2 + 1 = 3 |
第一个例子中的setNumber(number + 1); 其实等同于setNumber(n => number + 1);
queued update | n | returns |
---|---|---|
n => number + 1 | 0 | 0 + 1 = 1 |
n => number + 1 | 1 | 0 + 1 = 1 |
n => number + 1 | 2 | 0 + 1 = 1 |
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
}}>Increase the number</button>
</>
)
}
一样的,画出表格就知道最终的值,6
queued update | n | returns |
---|---|---|
n => number + 5 | 0 | 0 + 5 = 5 |
n => n + 1 | 5 | 5 + 1 = 6 |
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
setNumber(42);
}}>Increase the number</button>
</>
)
}
结果42
queued update | n | returns |
---|---|---|
n => number + 5 | 0 | 0 + 5 = 5 |
n => n + 1 | 5 | 5 + 1 = 6 |
n => 42 | 6 | 42 = 42 |