1. Reactフックとは
useState の使用法について説明する前に、React Hook とは何かを見てみましょう。
フックは実際にはステートフルな機能コンポーネントです。クロージャは反応フックの中核です。
閉鎖
クロージャは、実行コンテキスト A と、A で作成された関数 B の 2 つの部分で構成される特別なオブジェクトです。Bの実行時にAの変数オブジェクトにアクセスするとクロージャが生成されます。
// 执行上下文,这里暂时写为一个函数,它也可以指一个模块
const A = () => {
const a = "aaa"
const B = () => {
// 注意这里可以修改a的值
console.log(a)
// 当B执行时,如果访问了A中的变量,那就产生闭包,这里称A(执行上下文)为闭包
}
}
React コンポーネントを定義して他のモジュールで使用すると、クロージャが生成されます。
// 这里把A.js看成是一个模块
export const A = () => {
const a = 'aaa'
}
// B.js
import {
A } from './A.js'
const B = () => {
// 这里把B.js看成是另一个组件,引入A组件,并且访问A组件中的变量,此时形成闭包, B里可以修改a的值
console.log(a)
}
クロージャの特性により、A モジュール内の a 変数は永続化されるため、B 関数が再度実行されると、最後の B 関数実行終了時の a の値も取得できます。
クロージャの原則に基づいてカスタム useState を作成できます。
// state.js模块 对应上面的A.js
let state = null;
export const useState = (value) => {
// 第一次调用的时候没有初始值,因此使用传入的初始值赋值
state = state || value
function dispatch(newValue) => {
state = newValue
}
return [state, dispatch]
}
// 在其他模块中引入并使用 对应上面的B.js 相当于是一个hooks组件
import React from 'react'
import {
useState } from './state'
export default function Demo() {
const [count, setCount] = useState(0)
return <button onClick={
() => setCount(count + 1)}>{
count}</button>}
React は、トップダウンの一方向データ フロー メソッドを使用して独自のデータと状態を管理します。データは親コンポーネントによってのみトリガーされ、子コンポーネントに渡されます。そのため、react では state と props が変更されるとコンポーネントが再レンダリングされ、親コンポーネントが変更された場合は、親コンポーネントの下にある子コンポーネントも再レンダリングされます。
レンダリングメソッド:
クラスコンポーネント: レンダリングメソッドを再実行;
機能コンポーネント: 関数全体を再実行;
二 useState()
useState() の主な機能は状態を保存することであり、デフォルト値であるパラメーターを受け取ります。これは配列を返します。最初の配列はデータで、2 番目の配列はデータを操作するメソッドです。
簡単な例を見てみましょう。
import React, {
useState } from 'react';
function Bulbs() {
const [on, setOn] = useState(false);
const lightOn = () => setOn(true);
const lightOff = () => setOn(false);
//lightOn和lightOff实际上用lightSwitch一个方法就够了
const lightSwitch = () => setOn(on => !on);
return (
<>
<div className={
on ? 'bulb-on' : 'bulb-off'} />
<button onClick={
lightOn}>开灯</button>
<button onClick={
lightOff}>关灯</button>
</>
);
}
1. 使用方法
(1) useState は現在の状態の初期値として値を受け取ります。コンポーネントが初めてレンダリングされるときにのみ実行されます。関数をパラメータとして渡すこともできます。
関数を渡す例を次に示します。
const a = 10
const b = 20
const [count, setCount] = useState(() => {
return a + b
})
(2) コールバックを使用した状態更新
const [toggled, setToggled] = useState(false);
setToggled(toggled => !toggled);
const [count, setCount] = useState(0);
setCount(count => count + 1);
// 数组的修改要注意
const [items, setItems] = useState([]);
setItems(items => [...items, 'New Item']);
2. 注意すべき点
(1) useState() はトップレベルでのみ呼び出され、関数コンポーネントまたはカスタムフックの内部でのみ呼び出されます。ループ、条件分岐、入れ子関数では呼び出すことができません。
(2) 廃止された状態
クロージャは、外部スコープから変数を取り込む関数です。状態変数はレンダリング間で変化するため、クロージャは最新の状態値を持つ変数をキャプチャする必要があります。そうしないと、状態が古いという問題が発生する可能性があります。
function DelayedCount() {
const [count, setCount] = useState(0);
const handleClickAsync = () => {
setTimeout(function delay() {
setCount(count + 1);
}, 3000);
}
return (
<div>
{
count}
<button onClick={
handleClickAsync}>Increase async</button>
</div>
);
}
ボタンが素早く複数回クリックされ、count 変数に実際のクリック数が正しく記録されず、一部のクリックが食い込まれます。
この問題を解決するには、関数メソッドを使用してカウント状態を更新します。次のようにsetCount(count + 1);
変更するだけです。setCount(count => count + 1);