React.memo 小练习题 + 参考答案
🧩 React.memo 小练习题 + 参考答案
练习 1:基本使用
题目:
创建一个父组件,里面有两个状态:count
和 message
。
父组件渲染一个子组件 Message
,它只接收 message
作为 props,并在渲染时打印 "Message render"
。
点击按钮改变 count
,观察子组件是否重新渲染。
用 React.memo
优化 Message
,观察差异。
答案代码:
import React, { useState } from "react";const Message = React.memo(({ message }) => {console.log("Message render");return <h2>{message}</h2>;
});export default function App() {const [count, setCount] = useState(0);const [message, setMessage] = useState("Hello");return (<div><h1>Count: {count}</h1><Message message={message} /><button onClick={() => setCount(count + 1)}>Increment Count</button><button onClick={() => setMessage(message + "!")}>Change Message</button></div>);
}
练习 2:浅比较的局限性
题目:
父组件中维护一个 user = { name: "Tom" }
,把它作为 props 传给 UserCard
。
点击按钮时执行 setUser({ name: "Tom" })
。
观察即使数据没变,子组件还是会重新渲染。
尝试用 useMemo
固定对象引用,避免重新渲染。
答案代码:
import React, { useState, useMemo } from "react";const UserCard = React.memo(({ user }) => {console.log("UserCard render");return <h2>User: {user.name}</h2>;
});export default function App() {const [count, setCount] = useState(0);// ❌ 没优化// const user = { name: "Tom" };// ✅ 优化const user = useMemo(() => ({ name: "Tom" }), []);return (<div><h1>Count: {count}</h1><UserCard user={user} /><button onClick={() => setCount(count + 1)}>Increment Count</button></div>);
}
练习 3:结合 useCallback
题目:
父组件定义一个回调函数 handleClick
,传给子组件 ButtonChild
。
不使用 useCallback
时,子组件每次都会重新渲染。
用 useCallback
包装后,子组件不再重复渲染。
答案代码:
import React, { useState, useCallback } from "react";const ButtonChild = React.memo(({ onClick }) => {console.log("ButtonChild render");return <button onClick={onClick}>Child Button</button>;
});export default function App() {const [count, setCount] = useState(0);// ❌ 每次 App 渲染都会生成新函数// const handleClick = () => console.log("clicked");// ✅ useCallback 固定引用const handleClick = useCallback(() => console.log("clicked"), []);return (<div><h1>Count: {count}</h1><ButtonChild onClick={handleClick} /><button onClick={() => setCount(count + 1)}>Increment Count</button></div>);
}
练习 4:列表优化
题目:
创建一个父组件,渲染 100 个用户,每个用户是一个子组件 UserRow
。
点击“刷新时间”按钮,观察整个列表是否重新渲染。
给 UserRow
添加 React.memo
,避免不必要的渲染。
答案代码:
import React, { useState } from "react";const UserRow = React.memo(({ name }) => {console.log("Render UserRow:", name);return <li>{name}</li>;
});export default function App() {const [time, setTime] = useState(Date.now());const users = Array.from({ length: 100 }, (_, i) => `User ${i + 1}`);return (<div><h1>Time: {time}</h1><button onClick={() => setTime(Date.now())}>Refresh Time</button><ul>{users.map((u) => (<UserRow key={u} name={u} />))}</ul></div>);
}
练习 5:自定义比较函数
题目:
创建一个子组件 Profile
,接收 name
和 age
。
要求:只有 age
改变时才重新渲染。
使用 React.memo
的第二个参数实现。
答案代码:
import React, { useState } from "react";const Profile = React.memo(({ name, age }) => {console.log("Profile render");return (<div><h2>{name}</h2><p>Age: {age}</p></div>);},(prevProps, nextProps) => {return prevProps.age === nextProps.age; // 只在 age 改变时重新渲染}
);export default function App() {const [name, setName] = useState("Tom");const [age, setAge] = useState(20);return (<div><Profile name={name} age={age} /><button onClick={() => setName(name + "!")}>Change Name</button><button onClick={() => setAge(age + 1)}>Increment Age</button></div>);
}
练习 6:性能对比(进阶)
题目:
渲染一个 5000 行的大列表,每一行是 ItemRow
。
点击按钮时更新一个无关的状态,看看没有 React.memo
时所有子组件是否重新渲染。
加上 React.memo
后,对比性能变化。
答案代码:
import React, { useState } from "react";const ItemRow = React.memo(({ value }) => {console.log("Render:", value);return <div>{value}</div>;
});export default function App() {const [tick, setTick] = useState(0);const items = Array.from({ length: 5000 }, (_, i) => `Item ${i}`);return (<div><h1>Tick: {tick}</h1><button onClick={() => setTick(tick + 1)}>Update Tick</button>{items.map((item) => (<ItemRow key={item} value={item} />))}</div>);
}