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

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


练习 1:基本使用

题目 :

创建一个父组件,里面有两个状态:count 和 message。

父组件渲染一个子组件 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,接收 name 和 age。

要求:只有 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>
  );
}
相关推荐
花开盛夏^.^3 小时前
电脑打开多个浏览器Web窗口占用较大的运行内存的原因
前端·浏览器
Dxy12393102163 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷3 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
馒头不想说话3 小时前
实体店老板的24小时AI运营员工,写、剪、发全自动,省下一整个团队工资
前端
椒哥6 小时前
一天被问几十次"允许",我统计了 517 次,然后写了个插件
前端·javascript·github
风骏时光牛马6 小时前
生成一个AI稳定性治理及疑难问题分析标题,只需要一个标题,不需要其他的任何文本。
前端
莫西干式秃头6 小时前
用 AI + threejs 写了个浏览器里的 3D 动作游戏《武来》:砍怪、放技能、开 SU7
前端·人工智能·three.js
kyriewen6 小时前
我测了 6 种防请求竞态的写法:只有 1 种真能打
前端·javascript·程序员
孟健6 小时前
用 WorkBuddy 做个人名片网页,挂上开源设计技能后效果完全不同了
前端·人工智能·ai编程
IT_陈寒6 小时前
SpringBoot自动配置的坑,这次终于爬出来了
前端·人工智能·后端