useState和useContext深度解析
React Hooks 徹底改變了React組件的狀態(tài)管理和功能復(fù)用方式疹鳄,使得函數(shù)組件也能擁有類組件的功能。
useState:函數(shù)組件的狀態(tài)管理
簡介:
useState
是React中最基礎(chǔ)的Hook缎罢,它允許我們在函數(shù)組件中添加狀態(tài)。useState是React提供的一個內(nèi)置Hook,用于在函數(shù)組件中添加局部狀態(tài)慎宾。它接受一個初始值作為參數(shù)潜支,返回一個數(shù)組甸赃,數(shù)組的第一個元素是當(dāng)前狀態(tài),第二個元素是一個更新狀態(tài)的函數(shù)冗酿。
import React, { useState } from 'react';
function Example() {
// 初始化狀態(tài)count為0
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useState
返回的 setCount
函數(shù)用于更新狀態(tài)埠对。每次調(diào)用 setCount
時,React會重新渲染組件裁替,并根據(jù)新的狀態(tài)值重新生成虛擬DOM项玛,然后進(jìn)行高效的DOM diff,最終更新實際DOM弱判。
深入理解
useState
的工作原理襟沮,狀態(tài)更新的異步性及其對性能的影響。
- 狀態(tài)更新是異步的,這意味著在同一個事件循環(huán)中多次調(diào)用
setCount
开伏,React只會使用最后一次的值膀跌。 -
useState
不支持復(fù)雜對象的淺比較,如果需要基于前一個狀態(tài)更新狀態(tài)固灵,可以使用函數(shù)形式的setCount
捅伤,例如setCount(prevCount => prevCount + 1)
。
進(jìn)階應(yīng)用
結(jié)合useEffect處理副作用巫玻,如數(shù)據(jù)獲取與清理丛忆。
import React, { useState, useEffect } from 'react';
function Example() {
// 初始化狀態(tài)
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// 數(shù)據(jù)獲取函數(shù)
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch('https://api.example.com/data');
const json = await response.json();
setData(json);
setError(null);
} catch (err) {
setError(err.message);
setData(null);
} finally {
setLoading(false);
}
};
// useEffect監(jiān)聽data的變化,首次渲染時執(zhí)行
useEffect(() => {
fetchData();
}, []);
// 渲染UI
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return (
<div>
<h1>Data Retrieved Successfully</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default Example;
代碼示例解讀:首先使用 useState
創(chuàng)建了三個狀態(tài)變量:data
存儲獲取的數(shù)據(jù)大审,loading 表示數(shù)據(jù)是否正在加載蘸际,error
存儲任何可能出現(xiàn)的錯誤信息。
然后徒扶,我們定義了一個 fetchData
函數(shù)粮彤,用于異步獲取數(shù)據(jù)。這個函數(shù)中包含了錯誤處理和狀態(tài)更新邏輯姜骡。
接著导坟,我們使用 useEffect
來執(zhí)行數(shù)據(jù)獲取。useEffect
的第二個參數(shù)是一個依賴數(shù)組圈澈,這里傳入空數(shù)組意味著只在組件掛載后執(zhí)行一次惫周,即首次渲染時獲取數(shù)據(jù)。這樣可以確保在組件加載時獲取數(shù)據(jù)康栈,而不是在每次狀態(tài)更新時都重新獲取递递。
在 useEffect
的回調(diào)函數(shù)中,我們調(diào)用 fetchData
函數(shù)啥么。由于 fetchData
改變了 data
登舞、loading
和 error
的值,所以不需要將這些狀態(tài)變量添加到依賴數(shù)組中悬荣,因為它們的變化會觸發(fā)組件的重新渲染菠秒,從而自動執(zhí)行新的數(shù)據(jù)獲取。
useContext:共享狀態(tài)的上下文解決方案
簡介
useContext用于跨組件傳遞數(shù)據(jù)氯迂,無需顯式傳遞props践叠。
首先,我們需要創(chuàng)建一個Context:
import React from 'react';
const ThemeContext = React.createContext('light');
然后在組件中使用 useContext:
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function Button() {
const theme = useContext(ThemeContext);
return (
<button style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>
{theme === 'dark' ? 'Dark' : 'Light'}
</button>
);
}
深入理解
- 使用
useContext
的組件會在提供者(Provider)更新時重新渲染嚼蚀,即使該組件的其他狀態(tài)沒有變化禁灼。 - 如果多個組件訂閱同一個
Context
,它們都會在提供者狀態(tài)改變時重新渲染轿曙,可能導(dǎo)致不必要的性能開銷匾二∠溃可以通過React.memo
或shouldComponentUpdate
等策略優(yōu)化。 - 為了防止濫用察藐,只在需要跨多個層級共享狀態(tài)時使用
Context
,否則應(yīng)優(yōu)先考慮props
傳遞舟扎。
useState與useContext的組合應(yīng)用
結(jié)合 useState
和useContext
分飞,我們可以創(chuàng)建一個帶有主題切換功能的計數(shù)器應(yīng)用:
import React, { createContext, useState, useContext } from 'react';
// 創(chuàng)建ThemeContext
const ThemeContext = createContext('light');
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
{children}
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</ThemeContext.Provider>
);
}
function Counter() {
const theme = useContext(ThemeContext);
const [count, setCount] = useState(0);
return (
<div style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>
Click me ({theme})
</button>
</div>
);
}
function App() {
return (
<ThemeProvider>
<Counter />
</ThemeProvider>
);
}
export default App;
代碼示例解讀:ThemeProvider
使用 useState 管理主題狀態(tài),Counter
組件通過 useContext
訂閱主題睹限,同時使用 useState
管理計數(shù)器狀態(tài)譬猫。當(dāng)主題切換時,Counter
會重新渲染羡疗,顯示對應(yīng)主題的顏色染服。