ReactJS - 使用 useState



useState 是一个基本的 React Hook,它允许函数组件维护自己的状态,并根据状态变化重新渲染自身。useState 的签名如下:

const [ <state>, <setState> ] = useState( <initialValue> )

其中,

  • initialValue - 状态的初始值。状态可以指定为任何类型(数字、字符串、数组和对象)。

  • state - 用于表示状态值的变量。

  • setState - 函数变量,用于表示由 useState 返回的更新状态的函数。

setState 函数的签名如下:

setState( <valueToBeUpdated> )

其中,valueToBeUpdated 是要更新的状态的值。设置和更新用户名称的示例用法如下:

// initialize the state
const [name, setName] = useState('John')

// update the state
setName('Peter)

特性

useState 的显著特性如下:

函数参数 - 它接受一个函数(返回初始状态)而不是初始值,并且只在组件的初始渲染期间执行一次该函数。如果初始值的计算代价很高,这将有助于提高性能。

const [val, setVal] = useState(() => {
   var initialValue = null
   // expensive calculation of initial value
   return initialValue
})

验证先前值 - 它检查状态的当前值和先前值,并且只有当它们不同时,React 才会渲染其子元素并触发效果。这将提高渲染性能。

// ...
setName('John') // update the state and rerender the component
// ...
// ...
setName('John') // does not fire the rendering of the children because the value of the state have not changed.
// ...

批量更新多个状态 - React 在内部批量处理多个状态更新。如果必须立即进行多个状态更新,则可以使用 React 提供的特殊函数 flushSync,它将立即刷新所有状态更改。

flushSync(() => setName('Peter'))

应用状态 Hook

让我们创建一个登录表单组件,并使用 useState Hook 维护表单的值。

首先,使用以下命令创建并启动一个 React 应用:

create-react-app myapp
cd myapp
npm start

接下来,在组件文件夹下创建一个 React 组件 LoginForm (src/components/LoginForm.js)

import { useState } from 'react';
export default function LoginForm() {
   // render code
}

接下来,使用 useState Hook 创建两个状态变量 usernamepassword,如下所示:

import { useState } from 'react';
export default function LoginForm() {
   const [username, setUsername] = useState('')
   const [password, setPassword] = useState('')
   
   // render code
}

接下来,创建一个函数来验证登录数据,如下所示:

import { useState } from 'react';
export default function LoginForm() {
   const [username, setUsername] = useState('')
   const [password, setPassword] = useState('')
   
   let isEmpty = (val) => {
      if(val == null || val == '') {
         return true;
      } else {
         return false;
      }
   }
   
   let validate = (e) => {
      e.preventDefault()
      if(!isEmpty(username) && !isEmpty(password)) {
         alert(JSON.stringify({
            username: username,
            password: password
         }))
      } else {
         alert("Please enter username / password")
      }
   }
   // render code
}

这里,isEmpty 是一个函数,用于检查数据是否存在或为空。

接下来,渲染一个带有两个输入字段的登录表单,并使用状态变量 (usernamepassword)、状态更新方法 (setUsernamesetPassword) 和验证方法来处理表单。

import { useState } from 'react';
export default function LoginForm() {
   return (
      <div style={{ textAlign: "center", padding: "5px" }}>
         <form name="loginForm">
            <label for="username">Username: </label>
               <input id="username" name="username" type="text"
               value={username}
               onChange={(e) => setUsername(e.target.value)} />
            <br />
            <label for="password">Password: </label>
               <input id="password" name="password" type="password"
               value={password}
               onChange={(e) => setPassword(e.target.value)} />
            <br />
            <button type="submit" onClick={(e) => validate(e)}>Submit</button>
         </form>
      </div>
   )
}

这里,

  • onChange 使用 Hook 返回的状态设置函数。

  • onClick 使用验证函数来验证并显示用户输入的数据。

LoginForm 组件的完整代码如下:

import { useState } from 'react';
export default function LoginForm() {
   const [username, setUsername] = useState('')
   const [password, setPassword] = useState('')
   
   let isEmpty = (val) => {
      if(val == null || val == '') {
         return true;
      } else {
         return false;
      }
   }
   
   let validate = (e) => {
      e.preventDefault()
      if(!isEmpty(username) && !isEmpty(password)) {
         alert(JSON.stringify({
            username: username,
            password: password
         }))
      } else {
         alert("Please enter username / password")
      }
   }
   
   return (
      <div style={{ textAlign: "center", padding: "5px" }}>
         <form name="loginForm">
            <label for="username">Username: </label>
               <input id="username" name="username" type="text"
               value={username}
               onChange={(e) => setUsername(e.target.value)} />
            <br />
            <label for="password">Password: </label>
               <input id="password" name="password" type="password"
               value={password}
               onChange={(e) => setPassword(e.target.value)} />
            <br />
            <button type="submit" onClick={(e) => validate(e)}>Submit</button>
         </form>
      </div>
   )
}

接下来,更新根应用程序组件 App.js,如下所示:

import './App.css';
import HelloWorld from './components/HelloWorld';
import LoginForm from './components/LoginForm';
function App() {
   return (
      <LoginForm />
   );
}
export default App;

接下来,打开浏览器并检查应用程序。应用程序将使用状态变量收集用户输入的数据,并使用验证函数对其进行验证。如果用户输入了正确的数据,它将显示数据,如下所示:

Applying State Hook

否则,它将抛出错误,如下所示:

Applying State Hook

对象作为状态

在基于类的状态管理中,setState 方法支持状态对象的局部更新。例如,让我们考虑一下登录表单数据作为对象保存在状态中。

Applying State Hook
{
   username: 'John',
   password: 'secret'
}

使用 setState 更新用户名只会更新状态对象中的用户名并保留密码字段。

this.setState({
   username: 'Peter'
})

在 Hook 中,setData(由 useState 返回的函数)将更新整个对象,如下所示:

// create state
const [data, setDate] = useState({
   username: 'John',
   password: 'secret'
})
// update state - wrong
setData({
   username: 'Peter'
})

更新后的状态没有密码字段,如下所示:

{
   username: 'Peter'
}

为了解决这个问题,我们可以使用 JavaScript 中的扩展运算符,如下所示:

setData({
   ...data,
   username: 'Peter'
})

让我们通过转换 LoginForm 组件创建一个新组件,并使用对象状态变量,如下所示:

import { useState } from 'react';
export default function LoginFormObject() {
   const [data, setData] = useState({})
   let isEmpty = (val) => {
      if(val == null || val == '') {
         return true;
      } else {
         return false;
      }
   }
   let validate = (e) => {
      e.preventDefault()
      if(!isEmpty(data.username) && !isEmpty(data.password)) {
         alert(JSON.stringify(data))
      } else {
         alert("Please enter username / password")
      }
   }
   return (
      <div style={{ textAlign: "center", padding: "5px" }}>
         <form name="loginForm">
            <label for="username">Username: </label>
               <input id="username" name="username" type="text"
               value={data.username}
               onChange={(e) => setData( {...data, username: e.target.value} )} />
            <br />
            <label for="password">Password: </label>
               <input id="password" name="password" type="password"
               value={data.password}
               onChange={(e) => setData({...data, password: e.target.value})} />
            <br />
            <button type="submit" onClick={(e) => validate(e)}>Submit</button>
         </form>
      </div>
   )
}

这里,

  • 状态 保存在对象 (data) 中。

  • setDatauseState Hook 返回,并用作状态更新函数。

  • data.* 语法用于获取状态的详细信息。

  • ...data 扩展运算符与 setData 函数一起使用来更新状态。

总结

useState Hook 是一种在函数组件中进行状态管理的简单易行的方法。useState 可用于处理状态中的单个值或多个值。它支持基本数据类型和复杂对象。它允许使用多个状态设置函数 (set*) 并在内部进行批处理以简化流程。由于引入了 useState Hook,函数组件最终得到了改进,可以执行任何功能(从无状态到有状态)。

广告