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,函式元件最終得到了改進,可以執行任何功能(從無狀態到有狀態)。

廣告