React.memo 小练习题 + 参考答案

🧩 React.memo 小练习题 + 参考答案


练习 1:基本使用

题目

创建一个父组件,里面有两个状态:countmessage

父组件渲染一个子组件 Message,它只接收 message 作为 props,并在渲染时打印 "Message render"

点击按钮改变 count,观察子组件是否重新渲染。

React.memo 优化 Message,观察差异。

答案代码:

jsx 复制代码
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 固定对象引用,避免重新渲染。

答案代码:

jsx 复制代码
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 包装后,子组件不再重复渲染。

答案代码:

jsx 复制代码
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,避免不必要的渲染。

答案代码:

jsx 复制代码
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,接收 nameage

要求:只有 age 改变时才重新渲染。

使用 React.memo 的第二个参数实现。

答案代码:

jsx 复制代码
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 后,对比性能变化。

答案代码:

jsx 复制代码
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>
  );
}
相关推荐
zero13_小葵司2 小时前
Vue 3 前端工程化规范
前端·javascript·vue.js
Yolanda_20222 小时前
vue-sync修饰符解析以及切换iframe页面进行保存提示功能的思路
前端·javascript·vue.js
Pu_Nine_92 小时前
深入理解节流(Throttle):原理、实现与应用场景
javascript·性能优化·es6·节流·lodash 库
伍哥的传说2 小时前
Vite Plugin PWA – 零配置构建现代渐进式Web应用
开发语言·前端·javascript·web app·pwa·service worker·workbox
ai产品老杨2 小时前
解锁仓储智能调度、运输路径优化、数据实时追踪,全功能降本提效的智慧物流开源了
javascript·人工智能·开源·音视频·能源
GDAL2 小时前
Quat.js四元数完全指南
javascript·quaternion
alphageek82 小时前
Electron开源库入门教程:跨平台桌面应用框架
javascript·其他·electron·开源
小桥风满袖3 小时前
极简三分钟ES6 - ES8中字符串扩展
前端·javascript