React?useCallback使用方法詳解
1. useCallback 基礎(chǔ)概念
useCallback 是 React 的一個 Hook,用于記憶函數(shù)定義,避免在每次渲染時創(chuàng)建新的函數(shù)實例。它在需要將回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的子組件時特別有用。 當state變化的時候引起組件重新渲染執(zhí)行會導(dǎo)致某個方法被反復(fù)創(chuàng)建增加內(nèi)存負擔,這個時候可以使用useCallback將該函數(shù)進行緩存,只創(chuàng)建一次
1.1 基本語法
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b], // 依賴項數(shù)組
);
同樣的當依賴項省略時組件重新渲染都會執(zhí)行,當依賴項為空數(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ù)永遠不會改變
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)該在實際需要時才進行優(yōu)化。
到此這篇關(guān)于React useCallback使用方法詳解的文章就介紹到這了,更多相關(guān)React useCallback內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react+antd實現(xiàn)動態(tài)編輯表格數(shù)據(jù)
這篇文章主要為大家詳細介紹了react+antd實現(xiàn)動態(tài)編輯表格數(shù)據(jù),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
React路由的history對象的插件history的使用解讀
這篇文章主要介紹了React路由的history對象的插件history的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
React antd tabs切換造成子組件重復(fù)刷新
這篇文章主要介紹了React antd tabs切換造成子組件重復(fù)刷新,需要的朋友可以參考下2021-04-04
在react中對less實現(xiàn)scoped配置方式
這篇文章主要介紹了在react中對less實現(xiàn)scoped配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容
這篇文章主要介紹了React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05

