React?useCallback使用方法詳解
1. useCallback 基礎(chǔ)概念
useCallback 是 React 的一個 Hook,用于記憶函數(shù)定義,避免在每次渲染時創(chuàng)建新的函數(shù)實例。它在需要將回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的子組件時特別有用。 當(dāng)state變化的時候引起組件重新渲染執(zhí)行會導(dǎo)致某個方法被反復(fù)創(chuàng)建增加內(nèi)存負(fù)擔(dān),這個時候可以使用useCallback將該函數(shù)進(jìn)行緩存,只創(chuàng)建一次
1.1 基本語法
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b], // 依賴項數(shù)組
);
同樣的當(dāng)依賴項省略時組件重新渲染都會執(zhí)行,當(dāng)依賴項為空數(shù)組的時候只有組件初始化的時候會執(zhí)行一次,數(shù)組里有依賴項的時候依賴項發(fā)生變化的時候都會緩存一次
1.2 與普通函數(shù)的區(qū)別
function ParentComponent() {
const [count, setCount] = useState(0);
// ? 每次渲染都會創(chuàng)建新的函數(shù)實例
const handleClick = () => {
console.log('Clicked');
};
// ? 函數(shù)實例會被記憶,只在依賴項變化時更新
const handleClickMemoized = useCallback(() => {
console.log('Clicked');
}, []); // 空依賴數(shù)組,函數(shù)永遠(yuǎn)不會改變
return <ChildComponent onClick={handleClickMemoized} />;
}
2. useCallback 配合 React.memo 使用
2.1 基本示例
// 子組件使用 React.memo 優(yōu)化
const ChildComponent = React.memo(function ChildComponent({ onClick }) {
console.log("ChildComponent rendered");
return <button onClick={onClick}>Click me</button>;
});
// 父組件使用 useCallback
function ParentComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
// 使用 useCallback 記憶回調(diào)函數(shù)
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []); // 空依賴數(shù)組,因為不依賴任何值
return (
<div>
<input value={text} onChange={e => setText(e.target.value)} />
<p>Count: {count}</p>
<ChildComponent onClick={handleClick} />
</div>
);
}
2.2 帶有依賴項的示例
function SearchComponent({ onSearch }) {
const [searchTerm, setSearchTerm] = useState("");
const [searchHistory, setSearchHistory] = useState([]);
// 使用 useCallback 記憶搜索函數(shù)
const handleSearch = useCallback(() => {
if (searchTerm.trim()) {
onSearch(searchTerm);
setSearchHistory(prev => [...prev, searchTerm]);
}
}, [searchTerm, onSearch]); // 依賴 searchTerm 和 onSearch
return (
<div>
<input
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)}
/>
<SearchButton onClick={handleSearch} />
<SearchHistory items={searchHistory} />
</div>
);
}
// 優(yōu)化的子組件
const SearchButton = React.memo(function SearchButton({ onClick }) {
console.log("SearchButton rendered");
return <button onClick={onClick}>搜索</button>;
});
const SearchHistory = React.memo(function SearchHistory({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
});
3. 實際應(yīng)用場景
3.1 表單處理
function ComplexForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
// 記憶表單字段更新函數(shù)
const handleFieldChange = useCallback((fieldName) => (event) => {
setFormData(prev => ({
...prev,
[fieldName]: event.target.value
}));
}, []); // 不需要依賴項,因為使用了函數(shù)式更新
return (
<form>
<FormField
label="Name"
value={formData.name}
onChange={handleFieldChange('name')}
/>
<FormField
label="Email"
value={formData.email}
onChange={handleFieldChange('email')}
/>
<FormField
label="Message"
value={formData.message}
onChange={handleFieldChange('message')}
/>
</form>
);
}
const FormField = React.memo(function FormField({ label, value, onChange }) {
console.log(`${label} field rendered`);
return (
<div>
<label>{label}</label>
<input value={value} onChange={onChange} />
</div>
);
});
3.2 列表渲染優(yōu)化
function TodoList() {
const [todos, setTodos] = useState([]);
// 記憶添加任務(wù)函數(shù)
const handleAdd = useCallback((text) => {
setTodos(prev => [...prev, { id: Date.now(), text, completed: false }]);
}, []);
// 記憶切換完成狀態(tài)函數(shù)
const handleToggle = useCallback((id) => {
setTodos(prev =>
prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
}, []);
// 記憶刪除函數(shù)
const handleDelete = useCallback((id) => {
setTodos(prev => prev.filter(todo => todo.id !== id));
}, []);
return (
<div>
<AddTodo onAdd={handleAdd} />
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={handleToggle}
onDelete={handleDelete}
/>
))}
</div>
);
}
const TodoItem = React.memo(function TodoItem({ todo, onToggle, onDelete }) {
return (
<div>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => onDelete(todo.id)}>刪除</button>
</div>
);
});
4. 性能優(yōu)化最佳實踐
4.1 合理使用依賴項
function UserProfile({ userId, onUpdate }) {
// ? 只在 userId 或 onUpdate 變化時更新
const handleUpdate = useCallback(() => {
onUpdate(userId);
}, [userId, onUpdate]);
// ? 不必要的依賴項
const handleClick = useCallback(() => {
console.log('Clicked');
}, [userId]); // userId 不需要作為依賴項
}
4.2 避免過度優(yōu)化
// ? 簡單組件不需要使用 useCallback
function SimpleButton({ onClick }) {
return <button onClick={onClick}>Click me</button>;
}
// ? 復(fù)雜組件或頻繁重渲染的組件使用 useCallback
const ComplexComponent = React.memo(function ComplexComponent({ onAction }) {
// 復(fù)雜的渲染邏輯
return (
// ...
);
});
5. useCallback 與其他 Hooks 配合
5.1 配合 useEffect 使用
function DataFetcher({ query }) {
const [data, setData] = useState(null);
// 記憶獲取數(shù)據(jù)的函數(shù)
const fetchData = useCallback(async () => {
const response = await fetch(`/api/search?q=${query}`);
const result = await response.json();
setData(result);
}, [query]);
// 在 effect 中使用記憶的函數(shù)
useEffect(() => {
fetchData();
}, [fetchData]); // fetchData 作為依賴項
return <div>{/* 渲染數(shù)據(jù) */}</div>;
}
5.2 配合 useMemo 使用
function DataProcessor({ data, onProcess }) {
// 記憶處理函數(shù)
const processData = useCallback((item) => {
// 復(fù)雜的數(shù)據(jù)處理邏輯
return someExpensiveOperation(item);
}, []);
// 使用記憶的函數(shù)處理數(shù)據(jù)
const processedData = useMemo(() => {
return data.map(processData);
}, [data, processData]);
return (
<div>
{processedData.map(item => (
<ProcessedItem
key={item.id}
item={item}
onProcess={onProcess}
/>
))}
</div>
);
}
6. 注意事項
避免過度使用
- 只在性能確實受影響時使用
- 簡單組件和回調(diào)不需要使用 useCallback
正確設(shè)置依賴項
- 包含所有回調(diào)中使用的變量
- 避免不必要的依賴項
配合 React.memo 使用
- 單獨使用 useCallback 可能無法帶來性能提升
- 需要配合 React.memo 等優(yōu)化手段
考慮使用場景
- 頻繁重渲染的組件
- 復(fù)雜的計算或操作
- 傳遞給多個子組件的回調(diào)
通過合理使用 useCallback 和 React.memo,我們可以有效優(yōu)化 React 應(yīng)用的性能。但要記住,過度優(yōu)化可能會適得其反,應(yīng)該在實際需要時才進(jìn)行優(yōu)化。
到此這篇關(guān)于React useCallback使用方法詳解的文章就介紹到這了,更多相關(guān)React useCallback內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 關(guān)于react中useCallback的用法
- react中關(guān)于useCallback的用法
- 詳解react中useCallback內(nèi)部是如何實現(xiàn)的
- React Hooks之使用useCallback和useMemo進(jìn)行性能優(yōu)化方式
- React中memo useCallback useMemo方法作用及使用場景
- 解析React中useMemo與useCallback的區(qū)別
- react組件memo useMemo useCallback使用區(qū)別示例
- React?中?memo?useMemo?useCallback?到底該怎么用
- React中useCallback 的基本使用和原理小結(jié)
相關(guān)文章
詳解React Angular Vue三大前端技術(shù)
當(dāng)前世界中,技術(shù)發(fā)展非常迅速并且變化迅速,開發(fā)者需要更多的開發(fā)工具來解決不同的問題。本文就對于當(dāng)下主流的前端開發(fā)技術(shù)React、Vue、Angular這三個框架做個相對詳盡的探究,目的是為了解開這些前端技術(shù)的面紗,看看各自的廬山真面目。2021-05-05
react redux中如何獲取store數(shù)據(jù)并將數(shù)據(jù)渲染出來
這篇文章主要介紹了react redux中如何獲取store數(shù)據(jù)并將數(shù)據(jù)渲染出來,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
React動畫實現(xiàn)方案Framer Motion讓頁面自己動起來
這篇文章主要為大家介紹了React動畫實現(xiàn)方案Framer Motion讓頁面自己動起來,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10

