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>
  );
}
相关推荐
To_OC7 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
咩咩啃树皮8 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
阳光是sunny8 小时前
LangGraph中的Reducer是什么
前端·人工智能·后端
触底反弹8 小时前
一文搞懂 Tailwind CSS 弹性布局:从原理到实战
前端·css·html
阳光是sunny8 小时前
从链到图:LangGraph 入门基础全解析
前端·人工智能·后端
To_OC9 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn9 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
REDcker9 小时前
显示分辨率标准对照详解
前端·网络·分辨率·显示·屏幕
এ慕ོ冬℘゜10 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
武子康10 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端