组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段,单击轮播图上的“下一个”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记住”某些东西:当前输入值、当前图片、购物车。在 React 中,这种组件特有的记忆被称为 state。
学习
- 如何使用 useState Hook 添加 state 变量
useState
Hook 返回哪一对值- 如何添加多个 state 变量
- 为什么 state 被称作是局部的
useState Hook 提供了这两个功能:
- State 变量 用于保存渲染间的数据。
- State setter 函数 更新变量并触发 React 再次渲染组件。
添加一个 state 变量
要添加 state 变量,先从文件顶部的 React 中导入 useState
:
import { useState } from 'react';
以下是一个渲染作品文章的组件。点击 “Next” 按钮显示下一个作品并将 index
更改为 1
,再次点击又更改为 2
,以此类推。
import React, { useState } from 'react';
import {Button} from "antd";
const sculptureList = [
{
name: '云边有个小卖部',
artist: '张嘉佳',
description: '生命是有光的,在我熄灭以前,能够照亮你一点,就是我所有能做的了.我爱你,你要记得我',
},
{
name: '去有风的地方',
artist: '水阡墨',
description: '2222222222222222222222222222222222222',
},
{
name: '从你的全世界路过',
artist: '张嘉佳',
description: '33333333333333333333',
},
];
const App:React.FC = () => {
const [index, setIndex] = useState(0);
const handleClick=()=> {
setIndex(index + 1);
}
let sculpture = sculptureList[index];
return (
<>
<Button type="primary" onClick={handleClick}>
Next
</Button>
<h2>
<i>{sculpture.name} </i>
来自 {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<hr/>
<p>
{sculpture.description}
</p>
</>
);
}
export default App
剖析 useState
useState
的唯一参数是 state 变量的初始值。在这个例子中,index
的初始值被useState(0)
设置为 0
。
每次你的组件渲染时,useState
都会给你一个包含两个值的数组:
- state 变量 (
index
) 会保存上次渲染的值。 - state setter 函数 (
setIndex
) 可以更新 state 变量并触发 React 重新渲染组件。
以下是实际发生的情况:
const [index, setIndex] = useState(0);
- 组件进行第一次渲染。 因为你将
0
作为index
的初始值传递给useState
,它将返回[0, setIndex]
。 React 记住0
是最新的 state 值。 - 你更新了 state。当用户点击按钮时,它会调用
setIndex(index + 1)
。index
是0
,所以它是setIndex(1)
。这告诉 React 现在记住index
是1
并触发下一次渲染。 - 组件进行第二次渲染。React 仍然看到
useState(0)
,但是因为 React 记住 了你将index
设置为了1
,它将返回[1, setIndex]
。 - 以此类推!
赋予一个组件多个 state 变量
你可以在一个组件中拥有任意多种类型的 state 变量。该组件有两个 state 变量,一个数字 index
和一个布尔值 showMore
,点击 “Show Details” 会改变 showMore
的值:
import React, { useState } from 'react';
import {Button} from "antd";
const sculptureList = [
{
name: '云边有个小卖部',
artist: '张嘉佳',
description: '生命是有光的,在我熄灭以前,能够照亮你一点,就是我所有能做的了.我爱你,你要记得我',
},
{
name: '去有风的地方',
artist: '水阡墨',
description: '2222222222222222222222222222222222222',
},
{
name: '从你的全世界路过',
artist: '张嘉佳',
description: '33333333333333333333',
},
];
const App:React.FC = () => {
const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);
const handleClick=()=> {
setIndex(index + 1);
}
const handleMoreClick=()=> {
setShowMore(!showMore);
}
let sculpture = sculptureList[index];
return (
<>
<Button type="primary" onClick={handleClick}>
Next
</Button>
<h2>
<i>{sculpture.name} </i>
来自 {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<hr/>
<Button type="default" onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</Button>
<p>
{showMore && <p>{sculpture.description}</p>}
</p>
</>
);
}
export default App
State 是隔离且私有的
State 是屏幕上组件实例内部的状态。换句话说,如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!改变其中一个不会影响另一个。
在这个例子中,之前的 Gallery
组件以同样的逻辑被渲染了两次。试着点击每个画廊内的按钮。你会注意到它们的 state 是相互独立的:
import React, { useState } from 'react';
import {Button, Col, Row} from "antd";
const sculptureList = [
{
name: '云边有个小卖部',
artist: '张嘉佳',
description: '生命是有光的,在我熄灭以前,能够照亮你一点,就是我所有能做的了.我爱你,你要记得我',
},
{
name: '去有风的地方',
artist: '水阡墨',
description: '2222222222222222222222222222222222222',
},
{
name: '从你的全世界路过',
artist: '张嘉佳',
description: '33333333333333333333',
},
];
const Gallery=()=>{
const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);
const handleClick=()=> {
setIndex(index + 1);
}
const handleMoreClick=()=> {
setShowMore(!showMore);
}
let sculpture = sculptureList[index];
return (
<>
<Button type="primary" onClick={handleClick}>
Next
</Button>
<h2>
<i>{sculpture.name} </i>
来自 {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<hr/>
<Button type="default" onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</Button>
<p>
{showMore && <p>{sculpture.description}</p>}
</p>
</>
);
}
const App:React.FC = () => {
return(
<div>
<Row>
<Col span={12}><Gallery/></Col>
<Col span={12}><Gallery/></Col>
</Row>
</div>
)
}
export default App
这就是 state 与声明在模块顶部的普通变量不同的原因。 State 不依赖于特定的函数调用或在代码中的位置,它的作用域“只限于”屏幕上的某块特定区域。你渲染了两个 <Gallery />
组件,所以它们的 state 是分别存储的。
与 props 不同,state 完全私有于声明它的组件。父组件无法更改它。这使你可以向任何组件添加或删除 state,而不会影响其他组件。
摘要
- 当一个组件需要在多次渲染间“记住”某些信息时使用 state 变量。
- State 变量是通过调用
useState
Hook 来声明的。 - Hook 是以
use
开头的特殊函数。它们能让你 “hook” 到像 state 这样的 React 特性中。 - Hook 可能会让你想起 import:它们需要在非条件语句中调用。调用 Hook 时,包括
useState
,仅在组件或另一个 Hook 的顶层被调用才有效。 useState
Hook 返回一对值:当前 state 和更新它的函数。- 你可以拥有多个 state 变量。在内部,React 按顺序匹配它们。
- State 是组件私有的。如果你在两个地方渲染它,则每个副本都有独属于自己的 state。
文章及例子是参考React官方文档教程,不同的是我这里使用TS来写,开发环境:React+ts+antd