react hook之useState

本文详细介绍了React Hooks中的useState,包括启用、初始化、读取和更新状态的方法,以及如何处理过时状态和使用回调更新状态。通过示例展示了如何在函数组件中管理多种状态,并强调了使用useState时应注意的规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HooK是react16.8的新增特性,它可以让你在不编写class的情况下使用state以及其他的react的特性

状态是隐藏在组件中的信息,组件可以在父组件不知道的情况下修改其状态。函数组件默认是没有状态的,要使函数组件具有状态管理,可以使用useState() hook进行状态管理。
将状态添加到函数组件需要四个步骤:启用状态、初始化、读取和更新。(下面使用checkbox的选中和取消来展示案例)

启用状态

要讲函数组件转换为有状态的组件,需要告诉React:从’react’包中导入useState钩子,然后再组件函数的顶部调用。
大致如下:

import React, { useState } from 'react';

function App() {
  ... = useState(...);
  return (
    <div className="App"><input type="checkbox" /></div>
  );
}

export default App;

在App组件函数的第一行调用 useState()(暂时不考虑参数和返回值)。重要的是,在组件内部调用HooK会使该函数成为有状态的函数组件。
启用状态后,下一步就是初始化

初始化状态

开始时,checkbox没有选中,使用状态为false来初始化Hook:

import React, { useState } from 'react';

function App() {
  //  useState(false) 使用false初始化状态
  ... = useState(false);
  return (
    <div className="App"><input type="checkbox" /></div>
  );
}

export default App;

启用和初始化状态之后,如何读取它?来看看useState(false) 返回什么。

读取状态

当useState(false)被调用时,它返回一个数组,该数组的第一项是状态值

const stateArray = useState(false);
stateArray[0] // => 状态值

读取组件的状态:

import React, { useState } from 'react';

function App() {
  const stateArray = useState(false);
  return (
    <input type="checkbox" checked={stateArray[0]} />
  );
}

export default App;

useState(false) 返回一个数组,第一项包含状态值,该值当前为false(因为状态已用false初始化)。
可以使用解构赋值将状态赋值到变量checked上。

import React, { useState } from 'react';

function App() {
  const [checked] = useState(false);
  return (
    <input type="checkbox" checked={checked} />
  );
}

export default App;

checked状态变量保存状态值。
状态已经启用并初始化,现在可以读取了,但是如何更新呢,再看看useState() 返回什么。

更新状态

在读取的时候我们已经知道,useState() 返回一个数组。其中第一项是一个状态值,第二项是一个更新状态的函数。

const [state, setState] = useState(initState);

// 将状态更改为 ‘newState’ 并触发重新渲染
setState(newState);
// 重新渲染 ‘state’ 后的值为 ‘newState’

要更新组件的状态,需使用新状态调用更新器函数setState(newState)。组件重新渲染后,状态接收新值 newState。
当点击选中按钮时将状态更新为true,点击取消时更新为false。

import React, { useState } from 'react';

function App() {
  const [checked, setChecked] = useState(false);
  return (
    <div className="App">
      <input type="checkbox" checked={checked} />
      <button onClick={() => setChecked(true)}>选中</button>
      <button onClick={() => setChecked(false)}>取消</button>
    </div>
  );
}

export default App;

单击选中按钮时,setChecked() 函数将 checked 更新为true。单击取消时会将 checked 更新为 false。
状态一旦改变,React就会重新渲染组件,checked 变量获取新的状态值。
状态更新作为对提供一些新信息的事件和响应。这些事件包括按钮单击、http请求完成等,确保在事件回调或其他HooK回调中调用状态更新函数。

使用回调更新状态(函数式更新)
// const [state, setState] = useState(initState);
// setState(prevState => nextState);

import React, { useState } from 'react';

function App() {
  const [checked, setChecked] = useState(false);
  return (
    <div className="App">
      <input type="checkbox" checked={checked} />
      <button onClick={() => setChecked(checked => !checked)}>选中/取消</button>
    </div>
  );
}

export default App;

setChecked(checked => !checked) 使用函数更新状态

小结
  • 调用useState() HooK 来启用函数组件中的状态。
  • useState(initState) 的第一个参数 initState 是状态的初始值。
  • [state, setState] = useState(initState); 返回一个包含2个元素的数组:状态值和状态更新函数。
  • 使用新值调用状态更新器函数 setState(newState) 更新状态。或者可以使用一个回调 setState(prevState => nextState)来调用状态更新器,该回调将返回基于先去状态的新状态。
  • 调用状态更新器后,React确保重新渲染组件,使新状态变为当前状态。
多种状态

通过多次调用useState(), 一个函数组件可以拥有多个状态

import React, { useState } from 'react';

function App() {
  const [checked, setChecked] = useState(false);
  const [count, setCount] = useState(1);
  const ipt = Array(count).fill(<input type="checkbox" checked={checked} />)
  return (
    <div className="App">
      <div>{ipt}</div>
      <button onClick={() => setChecked(chec => !chec)}>选中/取消</button>
      <button onClick={() => setCount(count + 1)}>增加</button>
    </div>
  );
}

export default App;
// const [checked, setChecked] = useState(false); 管理checkbox的选中和取消
// const [count, setCount] = useState(1);  管理checkbox 的数量

多个状态可以在一个组件中正确工作。

状态的延迟初始化(惰性初始state)

initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始state需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的state,此函数只在初始渲染时被调用:

const [state, setState] = useState(() => {
  const initialState = someExpensiveComoutation(props);
  return initialState;
});
过时状态

闭包是一个从外部作用域捕获变量的函数。
闭包(例如时间处理程序,回调)可能会从函数组件作用域中捕获状态变量。由于状态变量在渲染之间变化,因此闭包应捕获具有最新状态值的变量。否则,如果闭包捕获了过时的状态值,则可能会遇到过时的状态问题。
来看看一个过时的状态是如何表现出来的。组件<DelayedCount>延迟3秒计数按钮点击的次数

import React, { useState } from 'react';
function DelayedCount() {
  const [count, setCount] = useState(0);
  const handleClickAsync = () => {
    setTimeout(() => {
      setCount(count + 1);
    }, 3000);
  }

  return (
    <div>
      {count}
      <button onClick={handleClickAsync}>Increase async</button>
    </div>
  );
}

快速多次点击按钮,count变量不能正确记录实际点击次数,有些点击被吃掉。定时器中的回调函数是一个过时的闭包,它从初始渲染(使用0初始化时)中捕获了过时的count变量。为了解决这个问题,使用函数方法来更新count状态:

...
const handleClickAsync = () => {
  setTimeout(() => {
	setCount(count => count + 1);
  }, 3000);
}
...

现在setCount(count => count + 1) 在回调函数中正确更新计数状态。React确保将最新状态值作为参数提供给更新状态函数,过时闭包的问题解决了。
快速单击按钮。延迟过去后,count 能正确表示点击次数。

HooK 使用规则

在使用useState() Hook 时,必须遵循 Hook 的规则

  • 仅顶层调用 Hook :不能在循环,条件,嵌套函数等中调用useState()。在多个useState()调用中,渲染之间的调用顺序必须相同。
  • 仅从React 函数调用 Hook:必须仅在函数组件或自定义钩子内部调用useState()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值