🎯 【專欄:精讀React Hooks】我用16篇文章詳細解讀16個React官方的Hook,每一篇都盡力做到比官方文檔更仔細且更易讀,同時提供了開源demo作為演示。如果你是新手,可以把這個專欄當作學習材料,如果你有一定經驗了,可以把這份專欄當作查缺補漏的資料。
專欄首發地址:J實驗室 - React Hooks
專欄演示地址:React Hooks Demo
加入「前端&全棧交流羣」
自從 React v16.8 版本以來,React Hooks 為我們提供了全新的編寫和思考 React 組件的方式。不僅管理狀態和生命週期變得更簡潔、更強大,Hooks 還引入了併發渲染和其他高級功能。本系列文章將詳細探討每一個 Hook,從基礎到高級。首篇,我們將探討最常用的 hook——useState。
useState 的基本用法
useState主要用於給組件添加狀態變量。注意,我們只能在組件的頂層或自定義的 Hooks 中調用useState。
初始化狀態
基礎定義
const [age, setAge] = useState(42);
懶初始化
對於需要計算得到的初始狀態,可以使用函數傳遞給useState。這樣,函數只在初次渲染時執行,而非每次渲染。
const [todos, setTodos] = useState(createInitialTodos); // 注意:傳遞函數本身,非執行結果
更新狀態
直接更新vs函數式更新
大部分情況,直接更新狀態即可:
setAge(newState);
但當新狀態依賴於前一個狀態時,推薦使用函數式更新。這確保了更新準確性,特別是在併發模式下。
setState(prevState => prevState + 1);
以下兩個例子展示函數式更新的重要性:
// 示例1: 使用函數式更新
import { useState } from 'react';
export default function Counter() {
const [age, setAge] = useState(42);
function increment() {
setAge(a => a + 1); // 函數式更新
}
return (
<>
<h1>Your age: {age}</h1>
<button onClick={() => {
increment();
increment();
increment();
}}>+3</button>
</>
);
}
// 結果:點擊 +3 時,age 更新為 45。
// 示例2: 使用直接更新
import { useState } from 'react';
export default function Counter() {
const [age, setAge] = useState(42);
function increment() {
setAge(age + 1); // 直接更新
}
return (
<>
<h1>Your age: {age}</h1>
<button onClick={() => {
increment();
increment();
increment();
}}>+3</button>
</>
);
}
// 結果:點擊 +3 時,可能只更新為 43。
對象與數組的更新
對象和數組的更新需要創建新的引用,而不是直接修改原狀態。
setForm({
...form,
name: e.target.value // 更新這個屬性
});
// 錯誤示例:
// form.name = e.target.value
setTodos([
...todos,
{
id: nextId++,
title: title,
done: false
}
]);
// 錯誤示例
// todos.push({
// id: nextId++,
// title: title,
// done: false
// });
// setTodos(todos);
函數的更新
把函數存儲到state裏是很少見的做法,但某些情況下,我們有可能需要這麼做。
先看一個錯誤的示例:
const [fn, setFn] = useState(someFunction);
function handleClick() {
setFn(someOtherFunction);
}
根據上文,我們知道這樣的用法是把函數的返回值存儲或更新到狀態中,並不是把函數存儲到狀態中。
如果你想在狀態中存儲一個函數,你需要使用一個箭頭函數來“包裹”它。這是正確的做法:
const [fn, setFn] = useState(() => someFunction);
function handleClick() {
setFn(() => someOtherFunction);
}
那麼我們什麼時候會需要這樣使用?這裏介紹一些可能的場景:
- 可配置的行為: 你可能有一個組件,它的行為可以由父組件進行配置。在這種情況下,你可以將函數作為狀態存儲,以便在組件的生命週期中更改或更新它。
- 動態創建的函數: 在某些情況下,你可能需要基於組件的某些屬性或狀態動態創建函數。將這些函數存儲為狀態可以確保你只在必要時重新創建它們。
- 回調和外部交互: 如果你的組件與外部系統交互,並且需要提供回調函數,你可能希望在狀態中存儲這些回調函數,以便在適當的時候更改或更新它們。
- 延遲執行的函數: 在某些情況下,你可能想要在將來的某個時間點執行函數(例如,使用
setTimeout)。將函數存儲為狀態可以確保即使組件的其他部分發生變化,你也可以訪問到最初的函數引用。 - 與第三方庫的集成: 有些第三方庫可能要求你提供並在後續更改函數。在這種情況下,將函數作為狀態存儲可能會更加方便。
結語
在這篇文章中,我們深入探討了 React 的useStateHook,從它的基礎用法到一些進階技巧。掌握好useState是走向 React 高手之路的關鍵一步。在未來的文章中,我們還將繼續探討其他的 Hooks。
專欄資源
專欄首發地址:👉 精讀React Hooks
專欄演示地址:👉 React Hooks Demos
進羣交流:👉加入「前端&Node交流羣」