ReactJS - 使用 useMemo:初學者指南

您好,有抱負的 React 開發者!今天,我們將深入探討 React 的強大 Hooks 之一:useMemo。別擔心你對編程是新手;我會一步一步地引導你理解這個概念,就像我這些年來對無數學生所做的一樣。所以,來一杯咖啡(或者茶,如果你喜歡的話),讓我們一起踏上這個令人興奮的旅程吧!

ReactJS - Using useMemo

useMemo 是什麼?

在我們深入細節之前,讓我們先了解 useMemo 是什麼。想象你正在烤餅乾(我喜歡這個比喻,因為,好吧,誰不喜歡餅乾呢?)你有一個需要一些複雜計算來確定完美數量的巧克力豆的配方。現在,你會在每次烤餅乾時重新計算這個數量,還是會寫下來重複使用它?這就是 useMemo 所做的——它記住(或者說“記錄”)一個計算的結果,這樣你就不必不必要地重複它。

在 React 的術語中,useMemo 是一個 Hook,它讓你可以在重新渲染之間緩存一個計算的結果。這就像有一個超級聰明的助手為你記住複雜的任務!

useMemo Hook 的簽名

讓我們看看如何實際使用 useMemo Hook:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

別慌!我知道這可能一開始看起來有點令人害怕,但我們來分解它:

  1. useMemo 是我們 Hook 的名字。
  2. 它接受兩個參數:
  • 一個執行我們計算的函數 (() => computeExpensiveValue(a, b))
  • 一個依賴性數組 ([a, b])
  1. 它返回一個記錄的值。

這樣想:useMemo 在說,“嘿 React,只有當 ab 改變時才重新運行這個計算。否則,就給我你上次記住的結果。”

使用 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>
);
}

讓我們分解這個:

  1. 我們有一個購物車,裡面有一些項目,每個項目都有名字和價格。
  2. 我們使用 useMemo 來計算購物車中所有項目的總價格。
  3. 計算只在 cart 改變時重新運行(這就是最後的 [cart] 所做的)。
  4. 我們顯示每個項目和總價格。

現在,這有什麼用呢?想象一下,如果計算總價格是一個非常複雜的操作(也許涉及到折扣、稅等)。沒有 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>
);
}

在這個例子中:

  1. 我們有一個待辦事項列表和一些過濾狀態。
  2. 我們使用 useMemo 來創建一個基於當前過濾器的過濾待辦事項列表。
  3. 過濾的列表只在 todosfilter 改變時重新計算。

這裡的魔法在於 filteredTodos 將總是保持同一個對象引用,除非 todosfilter 改變。這對於優化性能非常重要,特別是當將這個列表傳遞給子组件時。

總結

好了,各位!我們已經一起穿越了 useMemo 的領地,從理解其基本概念到在真實世界中應用它。記住,useMemo 就像你值得信賴的副手,總是在那裡幫助你通過避免不必要的計算來優化你的 React 應用程序。

這裡是一個我們已經討論過的方法的快速參考表:

方法 目的 語法
useMemo 記錄昂貴的計算 useMemo(() => computation, dependencies)

與編程中的任何工具一樣,明智地使用 useMemo。它對於優化性能非常好,但過度使用它會使代碼變得更複雜,而且沒有顯著的好處。就像我總是告訴我的學生,“能力越強,責任越大!”

持續練習,持續建造,最重要的是,對 React 保持樂趣。在你意識到之前,你將會創建出會讓有經驗的開發者都說“哇!”的應用程序。記住,如果你覺得卡住了,就想象你正在向一個橡皮鴨子解釋你的代碼。這招很靈,相信我!

祝快樂編程,未來的 React 大師們!

Credits: Image by storyset