如何釋放React?Hooks的力量
譯文譯者 | 李睿
審校 | 重樓
React是用于構(gòu)建用戶界面的一個(gè)流行JavaScript庫,多年來已經(jīng)發(fā)生了重大變化和改進(jìn)。React中最具顛覆性的新特性之一就是引入了Hooks。React Hooks徹底改變了開發(fā)者在函數(shù)組件中管理狀態(tài)和生命周期的方式。在這個(gè)全面的指南中,將深入研究React Hooks的世界,探索它們的優(yōu)點(diǎn)、用例,以及如何利用它們來編寫更干凈、更易于維護(hù)的React代碼。
介紹
由Facebook公司開發(fā)的React已經(jīng)成為構(gòu)建現(xiàn)代交互式Web應(yīng)用程序的首選庫。傳統(tǒng)上,React組件被編寫為具有復(fù)雜狀態(tài)和生命周期管理的類。然而,隨著React 16.8在2019年初的發(fā)布,React團(tuán)隊(duì)引入了Hooks,它使開發(fā)人員能夠在函數(shù)組件中使用狀態(tài)和其他React特性。React范式的這種轉(zhuǎn)變對(duì)開發(fā)人員編寫和構(gòu)建代碼的方式產(chǎn)生了深遠(yuǎn)的影響。
在這一指南中,將探索React Hooks的各個(gè)方面,從理解它們的核心概念到在現(xiàn)實(shí)場(chǎng)景中如何有效地使用。無論是React新手還是經(jīng)驗(yàn)豐富的開發(fā)人員,這一指南都旨在提供對(duì)React Hooks的全面了解。
什么是React Hooks?
React Hooks是讓用戶從函數(shù)組件中“掛鉤”React狀態(tài)和生命周期特性的函數(shù)。在Hooks出現(xiàn)之前,這些特性只能在類組件中使用。有了Hooks之后,函數(shù)組件現(xiàn)在能夠以更直接和更有表現(xiàn)力的方式管理狀態(tài)、執(zhí)行副作用和訪問場(chǎng)景。
React Hooks背后的主要?jiǎng)訖C(jī)是簡(jiǎn)化跨組件的重用有狀態(tài)邏輯,并完全消除對(duì)類組件的需求。Hooks是遵循命名約定的函數(shù):它們都以u(píng)se開頭。React提供了幾個(gè)內(nèi)置Hooks,可以創(chuàng)建自己的自定義Hooks來封裝可重用邏輯。
以下探索一下關(guān)鍵的Hook和它們的用例。
采用Hooks背后的動(dòng)機(jī)
在深入了解React Hooks的細(xì)節(jié)之前,重要的是要了解引入它們背后的動(dòng)機(jī):
重用有狀態(tài)邏輯
在類組件中,組件之間共享有狀態(tài)邏輯通常涉及復(fù)雜的模式,例如高階組件(HOC)和呈現(xiàn)props。這可能導(dǎo)致“包裝地獄”(wrapper hell),并使代碼更難理解。Hooks允許用戶重用有狀態(tài)邏輯,而無需更改組件層次結(jié)構(gòu)。這使得代碼更模塊化,更易于維護(hù)。
簡(jiǎn)化組件邏輯
隨著類組件所包含的邏輯的增長(zhǎng),類組件會(huì)變得很麻煩。Hooks允許用戶根據(jù)組件封裝的邏輯將組件拆分為更小、更集中的函數(shù)。這使得代碼更容易閱讀和維護(hù)。
消除對(duì)類的需求
類組件具有更陡峭的學(xué)習(xí)曲線,對(duì)于具有函數(shù)式編程背景的開發(fā)人員來說可能不太直觀。Hooks提供了一種更實(shí)用的方式來使用React,使開發(fā)人員更容易理解和使用該庫。
減少樣板代碼
類組件通常需要為生命周期方法和綁定編寫重復(fù)的代碼。Hooks消除了很多這樣的樣板文件,產(chǎn)生了更干凈、更簡(jiǎn)潔的代碼。
基本的Hooks
以下從基本構(gòu)建塊開始走上React Hooks之旅:
useState
useState Hooks允許函數(shù)組件管理狀態(tài)。它獲取一個(gè)初始狀態(tài)值,并返回一個(gè)包含當(dāng)前狀態(tài)的數(shù)組和一個(gè)用于更新狀態(tài)的函數(shù)。這里有一個(gè)基本的例子:
JavaScript
import React, { useState } from 'react';
function Counter() { const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div> ); }
export default Counter;
在本例中,使用useState初始化了一個(gè)初始值為0的計(jì)數(shù)狀態(tài)變量。當(dāng)點(diǎn)擊“count”按鈕時(shí),可以使用setCount函數(shù)更新計(jì)數(shù)狀態(tài)。
useEffect
useEffect Hooks使用戶能夠在函數(shù)組件中執(zhí)行副作用。副作用包括數(shù)據(jù)獲取、DOM操作等。useEffect有兩個(gè)參數(shù):一個(gè)包含副作用代碼的函數(shù)和一個(gè)可選的依賴項(xiàng)數(shù)組。
以下是一個(gè)在組件掛載時(shí),從API獲取數(shù)據(jù)的例子:
JavaScript
import React, { useState, useEffect } from 'react';
function DataFetching()
{
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data)); }, []);
// Empty dependency array means this effect runs once
return (
<div>
{data ? (
<ul>
{data.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
) : (
<p>Loading data...</p>
)}
</div>
); }
export default DataFetching;
在這個(gè)例子中,useEffect Hook在組件安裝時(shí)從API獲取數(shù)據(jù)(由于依賴項(xiàng)數(shù)組為空)。提取的數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)狀態(tài)變量中,組件在可用時(shí)呈現(xiàn)它。
這些基本的Hook為管理函數(shù)組件中的狀態(tài)和執(zhí)行副作用提供了基礎(chǔ)。然而,React提供了各種額外的Hooks來處理更復(fù)雜的場(chǎng)景。
額外的Hooks
React提供了幾個(gè)內(nèi)置的Hook來滿足組件邏輯的不同方面。以下是一些常用的附加鉤子:
useContext
useContext Hooks允許函數(shù)組件訪問父組件的場(chǎng)景。提供了一種跨組件樹共享值(如主題或身份驗(yàn)證狀態(tài))的方法,而無需人工傳遞props。
下面是一個(gè)使用useContext來訪問組件中的主題的例子:
JavaScript
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedButton() { const theme = useContext(ThemeContext);
return (
<button className={`btn btn-${theme}`}>Themed Button</button> ); }
export default ThemedButton;
在這個(gè)例子中,useContext從ThemeContext中檢索當(dāng)前主題,從而允許ThemedButton組件相應(yīng)地設(shè)置自己的樣式。
useReducer
useReducer Hook是useState的一種替代方案,更適合管理復(fù)雜的狀態(tài)邏輯。它接受一個(gè)reducer函數(shù)和一個(gè)初始狀態(tài),并返回當(dāng)前狀態(tài)和一個(gè)dispatch函數(shù)。
下面是一個(gè)使用useReducer的簡(jiǎn)單計(jì)數(shù)器的例子:
JavaScript
import React, { useReducer } from 'react';
function counterReducer(state, action) { switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state; } }
function Counter() {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
); }
export default Counter;
在這個(gè)例子中,定義了一個(gè)reducer函數(shù)counterReducer來處理狀態(tài)更新。useReducer Hook初始化狀態(tài),并提供一個(gè)分派函數(shù)來分派動(dòng)作。
useRef
useRef Hooks創(chuàng)建一個(gè)可變r(jià)ef對(duì)象。Refs通常用于訪問DOM、管理焦點(diǎn)或緩存不會(huì)觸發(fā)重新渲染的值。
以下是使用useRef關(guān)注輸入元素的示例:
JavaScript
import React, { useRef } from 'react';
function InputWithFocus() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
); }
export default InputWithFocus;
在這個(gè)例子中,inputRef ref被附加到input元素上,使用戶能夠在單擊“focus input”按鈕時(shí)對(duì)其進(jìn)行聚焦。
useCallback和useMemo
useCallback和useMemo Hooks用于通過記憶函數(shù)或計(jì)算值來優(yōu)化性能。useCallback存儲(chǔ)一個(gè)函數(shù),而useMemo存儲(chǔ)一個(gè)計(jì)算值。
以下是一個(gè)useMemo僅在數(shù)字發(fā)生變化時(shí)計(jì)算其平方的示例:
JavaScript
import { useState, useEffect } from 'react';
function useTimer(initialTime = 0) {
const [time, setTime] = useState(initialTime);
useEffect(() => {
const intervalId = setInterval(() => {
setTime((prevTime) => prevTime + 1);
}, 1000);
return () => {
clearInterval(intervalId);
};
}, []);
return time; }
export default useTimer;
在這個(gè)例子中,squaredNumber的值是使用useMemo來記憶的,所以只有當(dāng)數(shù)字狀態(tài)改變時(shí)才會(huì)重新計(jì)算。
這些額外的Hook為用戶的函數(shù)組件提供了靈活性和優(yōu)化機(jī)會(huì)。用戶可以混合和匹配這些Hooks以滿足應(yīng)用程序的特定需求。
自定義Hooks
雖然React提供了一組內(nèi)置的Hooks,但用戶也可以創(chuàng)建自己的自定義Hooks來封裝可重用的邏輯。自定義Hooks遵循相同的命名約定,并且可以在內(nèi)部使用現(xiàn)有的Hooks。
JavaScript
import { useState, useEffect } from 'react';
function useTimer(initialTime = 0) {
const [time, setTime] = useState(initialTime);
useEffect(() => {
const intervalId = setInterval(() => {
setTime((prevTime) => prevTime + 1);
}, 1000);
return () => {
clearInterval(intervalId);
};
}, []);
return time; }
export default useTimer;
在這個(gè)例子中,useTimer自定義Hook管理一個(gè)每秒遞增的計(jì)時(shí)器。它在內(nèi)部使用useState和useEffect Hook。
用戶可以在任何函數(shù)組件中使用這個(gè)自定義Hook來管理計(jì)時(shí)器,而無需復(fù)制計(jì)時(shí)器邏輯。
常見的Hooks
React Hooks為簡(jiǎn)化Web開發(fā)中的常見模式提供了許多可能性。以下來探索一些實(shí)際場(chǎng)景,其中Hooks可以特別有用:
數(shù)據(jù)獲取
從API或其他來源獲取數(shù)據(jù)是Web應(yīng)用程序中的常見任務(wù)。用戶可以使用useEffect Hook來獲取數(shù)據(jù)和管理加載狀態(tài)。以下是一個(gè)簡(jiǎn)單的例子:
JavaScript
import React, { useState, useEffect } from 'react';
function DataFetching() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, []);
return (
<div>
{loading ? (
<p>Loading data...</p>
) : (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
</div>
); }
export default DataFetching;
在本例中,使用useState來管理數(shù)據(jù)和加載狀態(tài),并使用useEffect在組件裝載時(shí)獲取數(shù)據(jù)。
表單處理
表單是大多數(shù)Web應(yīng)用程序的重要組成部分。React Hooks允許用戶更干凈地管理表單狀態(tài)和驗(yàn)證邏輯,從而簡(jiǎn)化了表單處理。以下是一個(gè)基本示例:
JavaScript
import React, { useState } from 'react';
function Form() {
const [formData, setFormData] = useState({
username: '', password: '', });
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData, [name]: value, }); };
const handleSubmit = (e) => {
e.preventDefault(); // Handle form submission with formData
};
return (
<form onSubmit={handleSubmit}>
<input type="text" name="username" value={formData.username}
onChange={handleChange}
/>
<input type="password" name="password" value={formData.password}
onChange={handleChange}
/>
<button type="submit">Submit</button>
</form>
); }
export default Form;
在這個(gè)例子中,使用useState Hook來管理表單數(shù)據(jù),并使用handleChange函數(shù)來更新表單狀態(tài)。
結(jié)論
在這篇指南中,從React Hooks的介紹和動(dòng)機(jī)到實(shí)際示例和常見模式,走遍了React Hooks的世界。React Hooks徹底改變了開發(fā)人員編寫React組件的方式,使函數(shù)組件比以往任何時(shí)候都更加強(qiáng)大和富有表現(xiàn)力。
React Hooks如今已經(jīng)成為React開發(fā)人員工具包中的重要工具,可以提高代碼的可讀性、可維護(hù)性和可重用性。無論是想要開始使用React的初學(xué)者,還是想要重構(gòu)代碼庫的經(jīng)驗(yàn)豐富的開發(fā)人員,React Hooks都提供了一種現(xiàn)代而有效的方式來構(gòu)建健壯的Web應(yīng)用程序。
原文標(biāo)題:Unleashing the Power of React Hooks,作者:Atul Naithani