「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」。
这是React清风拂面系列第六篇,上一篇请看这里
为什么需要状态
import { sculptureList } from './data.js';
export default function Gallery() {
let index = 0;
function handleClick() {
index = index + 1;
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
</>
);
}
先看上面的代码,完整演示这里 handleClick 的本意是想切换数组里面的下一个对象,但是上面的代码无法达到目的。
主要原因在于:
- 本地变量index无法再2次渲染间保持状态。React每次刷新组件都是重置,因为index始终是初始值。
- 上面的写法无法触发React组件的render函数,也就是无法触发重新渲染。
所以,这里需要一个特殊的函数来满足上面两个要求useState
.
useState 符合下面2个条件:
- 在多次渲染之间可以保持状态,不会因为每次刷新而重置。
- 可以触发React的render函数,更新视图。
用法
const [index, setIndex] = useState(0);
之前文章说过,useState传入的值是index的默认值。index是变量,setIndex是更新index的函数。
代码改成下面结构,完整看这里
import { useState } from 'react';
import { sculptureList } from './data.js';
export default function Gallery() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
</>
);
}
第一个Hook
useState是你碰到的第一个Hook,在React里面Hook是一大类,都是以use开头如useXX的函数。
Hooks是一种特殊的函数,与React框架产生紧密联系。
Hooks的规则:
- 以use开头。
- 放在函数的头部,无法放在条件判断,循环或者内嵌等。
如果你违反规则,React库会报错。
多个state变量
可以用useState 定义多个变量,代码这里
export default function Gallery() {
const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);
}
多个变量还是都放在一个对象里面,主要看变量之间是否有关联,如果是内聚性高,就比较合适放在一个对象。
这里面我们定义了2个useState,如果说我们调用setShowMore(index)
React能查出这个错误呢。答案是不能。
因为 React Hooks 本质上是数组,我们每次调用useState,就是移动数组里面的下标。
Hooks源码简化版
let componentHooks = [];
let currentHookIndex = 0;
function useState(initialState) {
let pair = componentHooks[currentHookIndex];
if (pair) {
currentHookIndex++;
return pair;
}
//将函数入参当做默认值
pair = [initialState, setState];
//setState接受入参保存为下一次的state,更新Dom。
function setState(nextState) {
pair[0] = nextState;
updateDOM();
}
//保存到数组
componentHooks[currentHookIndex] = pair;
currentHookIndex++;
return pair;
}
另外,state属于函数的组件的私有变量,初始化多个组件实例,state之间不影响。
具体可看这个例子
import Gallery from './Gallery.js';
export default function Page() {
return (
<div className="Page">
<Gallery />
<Gallery />
</div>
);
}