使用React和TypeScript来保持组件的状态
React官方网站的文档已于2023年3月16日进行了修订(请参考「Introducing react.dev」)。本文概括了基本解释的「State: A Component’s Memory」一文,并增加了TypeScript的代码。但是,我们省略了针对初学者的基础JavaScript解释部分。
此外,有关本系列解说的其他文章,请参考”React + TypeScript: 学习React官方文档的基本解说《学习React》”。
根据与组件的交互,可能需要改变屏幕中的内容。例如,以下情况可能需要改变屏幕中的内容。
-
- フォームに入力したときテキストフィールドの更新。
-
- カルーセルで[つぎへ]のボタンをクリックしたときの画像の切り替え。
- 商品の[購入]ボタンクリックによるショッピングカートへの追加。
在React中,组件必须记住这些变更的当前值。每个组件都有一个称为状态(state)的机制,在其中可以存储值。此时,无法使用局部变量。
-
- 组件是函数,因此当React进行下一次渲染时,局部变量的值不会被保留。
- 即使局部变量的值发生变化,也不会触发重新渲染。这意味着React不知道应该使用新数据重新渲染组件。
使用状态变量
应该采取以下两个步骤来使用新数据更新组件。
-
- 在组件之间必须保留数据的值。
- 使用新的数据在React中重新渲染组件(再次渲染)。
在这里使用的是useState钩子,返回值是一个由以下两个元素组成的数组。
-
- 状态变量: 在渲染之间保存数据。
状态设置函数: 是一种设置状态变量的函数,告诉React重新渲染组件。
以下是構文的內容。返回的數組元素的變量或函數的名稱可以自由決定,但通常情況下,將狀態變量名前面添加”set”前綴成設定函數名稱。參數(initialState)是變量的初始值,如果使用TypeScript,請盡可能提供(參見”useState”)。
const [state, setState] = useState(initialState)
以下是一个示例代码,展示了如何使用useState钩子。状态变量index代表展示在Gallery组件中的页面信息。当点击按钮时,会前进到下一个页面,所以处理函数handleClick会通过设置函数setIndex来递增状态变量的值。
import { MouseEventHandler, useState } from 'react';
export default function Gallery() {
const [index, setIndex] = useState(0);
const handleClick: MouseEventHandler = () => {
setIndex(index + 1);
};
}
以下是根模块src/App.tsx的代码。状态变量会被保留,当值发生变化时,组件将重新渲染。关于要加载的数据(src/data.ts),请参考后面的样本001。点击[Next]按钮将切换显示在屏幕上的信息。
import { MouseEventHandler, useState } from 'react';
import { sculptureList } from './data';
export default function Gallery() {
const [index, setIndex] = useState(0);
const handleClick: MouseEventHandler = () => {
setIndex((index + 1) % sculptureList.length);
};
const { name, artist, description, url, alt } = sculptureList[index];
return (
<>
<button onClick={handleClick}>Next</button>
<h2>
<i>{name} </i>
by {artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img src={url} alt={alt} />
<p>{description}</p>
</>
);
}
type Sculpture = {
name: string;
artist: string;
description: string;
url: string;
alt: string;
};
export const sculptureList: Sculpture[] = [
{
name: "Homenaje a la ",
artist: "Marta Colvin Andrade",
description:
"Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.",
url: "https://i.imgur.com/Mx7dA2Y.jpg",
alt:
"A bronze statue of two crossed hands delicately holding a human brain in their fingertips."
},
// ...[中略]...
];
フック是以use开头的函数名。它是一个特殊的函数,提供各种功能,仅在React渲染过程中可用。useState也是其中之一。请注意,只能在组件或自定义钩子的顶层调用钩子。请注意,无法从条件、循环或嵌套函数中调用钩子。
状态和渲染将按照以下流程逐渐变化。
-
- 组件的初始渲染: React保持的状态变量的当前值是初始值。
-
- 状态更新: 当状态设置函数改变变量值时,React将其视为最新值并开始进行重新渲染。
- 组件的再渲染: useState的参数保持不变,仍为初始值。然而,状态变量会保持最新值。
给组件提供多个状态变量。
状態变量的数量和数据类型不受限制。下面的代码示例确定了两个状态变量(index和showMore)。两者的值更新是通过按钮点击(onClick)事件的处理函数(handleClick和handleMoreClick)完成的(示例001)。
import { MouseEventHandler, useState } from 'react';
import { sculptureList } from './data';
export default function Gallery() {
const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);
const handleClick: MouseEventHandler = () => {
setIndex((index + 1) % sculptureList.length);
setShowMore(false);
};
const handleMoreClick: MouseEventHandler = () => {
setShowMore(!showMore);
};
const { name, artist, description, url, alt } = sculptureList[index];
return (
<>
<button onClick={handleClick}>Next</button>
<h2>
<i>{name} </i>
by {artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<button onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</button>
{showMore && <p>{description}</p>}
<img src={url} alt={alt} />
</>
);
}
React + TypeScript:状态:组件的记忆 01
在useState的第一次调用中,状态变量将被初始化为参数值。当状态变量被更新后,在随后的渲染中,useState返回的状态变量值将是最新值而不是初始值。React是如何确保正确引用保持的值的?
在渲染一个组件时,钩子函数会按照特定的顺序被调用(因此,钩子函数必须在顶层被调用)。在内部,React会以数组形式维护每个组件的状态变量和设置函数的组合。然后,它会将这些组合添加到数组中,并传递给组件(参见「React如何知道返回哪个状态?」)。
状态是独立和私密的。
每个屏幕组件实例具有局部状态。如果渲染同一组件两次,则它们将具有完全独立的状态。改变其中一个状态不会影响另一个状态。即使将相同的组件放置在屏幕上两次,如果它们具有不同的状态,那么它们可以具有不同的值。状态是独立保持在每个组件之间的。
属性是从父组件传递的。然而,父组件并不知道或无法更改状态。状态是声明组件独有的私有数据。因此,可以添加或删除状态,而不会影响其他组件(请参阅“状态是隔离和私有的”)。
总结
在这篇文章中,我对以下主题进行了解释。
-
- コンポーネントのレンダリング間で情報を保持したいときに使うのが状態変数です。
useStateフックは状態変数を宣言します。
useStateフックの戻り値は、状態変数と状態設定関数を要素とした配列です。
フックは、コンポーネントまたはカスタムフックのトップレベルで呼び出さなければなりません。
状態変数は複数宣言できます。内部的にReactが値を対応させるのは、フックの呼び出し順です。
状態はコンポーネントごとにプライベートに扱われます。同じコンポーネントを複数レンダリングしても、状態の値はそれぞれ別です。