ReactJS - 使用 useMemo:初學者指南
您好,有抱負的 React 開發者!今天,我們將深入探討 React 的強大 Hooks 之一:useMemo。別擔心你對編程是新手;我會一步一步地引導你理解這個概念,就像我這些年來對無數學生所做的一樣。所以,來一杯咖啡(或者茶,如果你喜歡的話),讓我們一起踏上這個令人興奮的旅程吧!
useMemo 是什麼?
在我們深入細節之前,讓我們先了解 useMemo 是什麼。想象你正在烤餅乾(我喜歡這個比喻,因為,好吧,誰不喜歡餅乾呢?)你有一個需要一些複雜計算來確定完美數量的巧克力豆的配方。現在,你會在每次烤餅乾時重新計算這個數量,還是會寫下來重複使用它?這就是 useMemo 所做的——它記住(或者說“記錄”)一個計算的結果,這樣你就不必不必要地重複它。
在 React 的術語中,useMemo 是一個 Hook,它讓你可以在重新渲染之間緩存一個計算的結果。這就像有一個超級聰明的助手為你記住複雜的任務!
useMemo Hook 的簽名
讓我們看看如何實際使用 useMemo Hook:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
別慌!我知道這可能一開始看起來有點令人害怕,但我們來分解它:
-
useMemo
是我們 Hook 的名字。 - 它接受兩個參數:
- 一個執行我們計算的函數 (
() => computeExpensiveValue(a, b)
) - 一個依賴性數組 (
[a, b]
)
- 它返回一個記錄的值。
這樣想:useMemo 在說,“嘿 React,只有當 a
或 b
改變時才重新運行這個計算。否則,就給我你上次記住的結果。”
使用 useMemo Hook
現在,讓我們看看 useMemo 在真實世界範例中的應用。想象我們正在為線上商店建立一個購物車(因為誰不喜歡線上購物呢?)
import React, { useMemo, useState } from 'react';
function ShoppingCart() {
const [cart, setCart] = useState([
{ id: 1, name: "React 標誌 T 恤", price: 20 },
{ id: 2, name: "React 夾克", price: 40 },
{ id: 3, name: "React 帽子", price: 15 }
]);
const totalPrice = useMemo(() => {
console.log("計算總價格...");
return cart.reduce((total, item) => total + item.price, 0);
}, [cart]);
return (
<div>
<h2>你的購物車</h2>
{cart.map(item => (
<div key={item.id}>{item.name} - ${item.price}</div>
))}
<h3>總計:${totalPrice}</h3>
</div>
);
}
讓我們分解這個:
- 我們有一個購物車,裡面有一些項目,每個項目都有名字和價格。
- 我們使用
useMemo
來計算購物車中所有項目的總價格。 - 計算只在
cart
改變時重新運行(這就是最後的[cart]
所做的)。 - 我們顯示每個項目和總價格。
現在,這有什麼用呢?想象一下,如果計算總價格是一個非常複雜的操作(也許涉及到折扣、稅等)。沒有 useMemo
,React 會在每次组件重新渲染時重新計算這個值,即使購物車沒有改變。有了 useMemo
,它只在必要時才重新計算,這樣可以節省大量的處理時間!
保持引用
useMemo 的另一個超級酷的功能是它能够保持引用。 “那是什麼?”我聽到你問。讓我用另一個例子來解釋。
想象你正在建立一個待辦事項列表應用(因為每個程序員都在某個時候建立過一個,相信我!)。你想要根據它們的狀態過濾任務。
import React, { useMemo, useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "學習 React", completed: false },
{ id: 2, text: "建立惊人的應用程序", completed: false },
{ id: 3, text: "改變世界", completed: false }
]);
const [filter, setFilter] = useState('all');
const filteredTodos = useMemo(() => {
console.log("過濾待辦事項...");
switch(filter) {
case 'completed':
return todos.filter(todo => todo.completed);
case 'active':
return todos.filter(todo => !todo.completed);
default:
return todos;
}
}, [todos, filter]);
return (
<div>
<h2>我的待辦事項列表</h2>
<button onClick={() => setFilter('all')}>全部</button>
<button onClick={() => setFilter('active')}>活動中</button>
<button onClick={() => setFilter('completed')}>已完成</button>
{filteredTodos.map(todo => (
<div key={todo.id}>{todo.text}</div>
))}
</div>
);
}
在這個例子中:
- 我們有一個待辦事項列表和一些過濾狀態。
- 我們使用
useMemo
來創建一個基於當前過濾器的過濾待辦事項列表。 - 過濾的列表只在
todos
或filter
改變時重新計算。
這裡的魔法在於 filteredTodos
將總是保持同一個對象引用,除非 todos
或 filter
改變。這對於優化性能非常重要,特別是當將這個列表傳遞給子组件時。
總結
好了,各位!我們已經一起穿越了 useMemo 的領地,從理解其基本概念到在真實世界中應用它。記住,useMemo 就像你值得信賴的副手,總是在那裡幫助你通過避免不必要的計算來優化你的 React 應用程序。
這裡是一個我們已經討論過的方法的快速參考表:
方法 | 目的 | 語法 |
---|---|---|
useMemo | 記錄昂貴的計算 | useMemo(() => computation, dependencies) |
與編程中的任何工具一樣,明智地使用 useMemo。它對於優化性能非常好,但過度使用它會使代碼變得更複雜,而且沒有顯著的好處。就像我總是告訴我的學生,“能力越強,責任越大!”
持續練習,持續建造,最重要的是,對 React 保持樂趣。在你意識到之前,你將會創建出會讓有經驗的開發者都說“哇!”的應用程序。記住,如果你覺得卡住了,就想象你正在向一個橡皮鴨子解釋你的代碼。這招很靈,相信我!
祝快樂編程,未來的 React 大師們!
Credits: Image by storyset