React第二十章(useMemo) [复制链接]
发表于 2025-11-16 00:17:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
useMemo

useMemo 是 React 提供的一个性能优化 Hook。它的紧张功能是制止在每次渲染时实验复杂的盘算和对象重修。通过影象上一次的盘算效果,仅当依赖项变革时才会重新盘算,进步了性能,有点类似于Vue的computed。
React.memo

React.memo 是一个 React API,用于优化性能。它通过影象上一次的渲染效果,仅当 props 发生变革时才会重新渲染, 制止重新渲染。
用法

利用 React.memo 包裹组件[一样平常用于子组件],可以制止组件重新渲染。
  1. import React, { memo } from 'react';
  2. const MyComponent = React.memo(({ prop1, prop2 }) => {
  3.   // 组件逻辑
  4. });
  5. const App = () => {
  6.   return <MyComponent prop1="value1" prop2="value2" />;
  7. };
复制代码
React.memo 案例

起首明白 React 组件的渲染条件:

  • 组件的 props 发生变革
  • 组件的 state 发生变革
  • useContext 发生变革
我们来看下面这个例子,这个例子没有利用 memo 举行缓存,以是每次父组件的 state 发生变革,子组件都会重新渲染。
而我们的子组件只用到了 user 的信息,但是父组件每次 search 发生变革,子组件也会重新渲染, 如许就就造成了没须要的渲染以是我们利用 memo 缓存。
  1. import React, { useMemo, useState } from 'react';
  2. interface User {
  3.    name: string;
  4.    age: number;
  5.    email: string;
  6. }
  7. interface CardProps {
  8.    user: User;
  9. }
  10. const Card = function ({ user }: CardProps) { // [!code --]
  11. const Card = React.memo(function ({ user }: CardProps) { // [!code ++]
  12.    console.log('Card render'); // 每次父组件的 state 发生变化,子组件都会重新渲染
  13.    const styles = {
  14.       backgroundColor: 'lightblue',
  15.       padding: '20px',
  16.       borderRadius: '10px',
  17.       margin: '10px'
  18.    }
  19.    return <div style={styles}>
  20.       <h1>{user.name}</h1>
  21.       <p>{user.age}</p>
  22.       <p>{user.email}</p>
  23.    </div>
  24. } // [!code --]
  25. }) // [!code ++]
  26. function App() {
  27.    const [users, setUsers] = useState<User>({
  28.       name: '张三',
  29.       age: 18,
  30.       email: 'zhangsan@example.com'
  31.    });
  32.    const [search, setSearch] = useState('');
  33.    return (
  34.       <div>
  35.          <h1>父组件</h1>
  36.          <input value={search} onChange={(e) => setSearch(e.target.value)} />
  37.          <Card user={users} />
  38.       </div>
  39.    );
  40. }
  41. export default App;
复制代码
当我们利用 memo 缓存后,只有 user 发生变革时,子组件才会重新渲染, 而 search 发生变革时,子组件不会重新渲染。
  1. import React, { useMemo, useState } from 'react';
  2. interface User {
  3.    name: string;
  4.    age: number;
  5.    email: string;
  6. }
  7. interface CardProps {
  8.    user: User;
  9. }
  10. const Card = React.memo(function ({ user }: CardProps) {
  11.    console.log('Card render');
  12.    const styles = {
  13.       backgroundColor: 'lightblue',
  14.       padding: '20px',
  15.       borderRadius: '10px',
  16.       margin: '10px'
  17.    }
  18.    return <div style={styles}>
  19.       <h1>{user.name}</h1>
  20.       <p>{user.age}</p>
  21.       <p>{user.email}</p>
  22.    </div>
  23. })
  24. function App() {
  25.    const [users, setUsers] = useState<User>({
  26.       name: '张三',
  27.       age: 18,
  28.       email: 'zhangsan@example.com'
  29.    });
  30.    const [search, setSearch] = useState('');
  31.    return (
  32.       <div>
  33.          <h1>父组件</h1>
  34.          <input value={search} onChange={(e) => setSearch(e.target.value)} />
  35.          <div>
  36.             <button onClick={() => setUsers({
  37.                name: '李四',
  38.                age: Math.random() * 100,
  39.                email: 'lisi@example.com'
  40.             })}>更新user</button>
  41.          </div>
  42.          <Card user={users} />
  43.       </div>
  44.    );
  45. }
  46. export default App;
复制代码
React.memo 总结


  • 利用场景

    • 当子组件吸取的 props 不常常变革时
    • 当组件重新渲染的开销较大时
    • 当须要制止不须要的渲染时

  • 优点

    • 通过影象化制止不须要的重新渲染
    • 进步应用性能
    • 镌汰资源斲丧

  • 注意事项

    • 不要过分利用,只在确实须要优化的组件上利用
    • 对于简朴的组件,利用 memo 的开销大概比重新渲染还大
    • 如果 props 常常变革, memo 的效果会大打扣头

useMemo 用法
  1. import React, { useMemo, useState } from 'react';
  2. const App = () => {
  3.    const [count, setCount] = useState(0);
  4.    const memoizedValue = useMemo(() => count, [count]);
  5.    return <div>{memoizedValue}</div>;
  6. }
复制代码
参数

入参

  • 回调函数:Function:返回须要缓存的值
  • 依赖项:Array:依赖项发生变革时,回调函数会重新实验(实验时机跟useEffect类似)
返回值

  • 返回值:返回须要缓存的值(返回之后就不是函数了)
useMemo 案例

我们来看下面这个例子,这个例子没有利用 useMemo 举行缓存,以是每次 search 发生变革, total 都会重新盘算,如许就造成了没须要的盘算以是我们可以利用 useMemo 缓存,由于我们的 total 跟 search 没有关系,那么如果盘算的逻辑比力复杂,就造成了性能题目。
  1. import React, { useMemo, useState } from 'react';
  2. function App() {
  3.    const [search, setSearch] = useState('');
  4.    const [goods, setGoods] = useState([
  5.       { id: 1, name: '苹果', price: 10, count: 1 },
  6.       { id: 2, name: '香蕉', price: 20, count: 1 },
  7.       { id: 3, name: '橘子', price: 30, count: 1 },
  8.    ]);
  9.    const handleAdd = (id: number) => {
  10.       setGoods(goods.map(item => item.id === id ? { ...item, count: item.count + 1 } : item));
  11.    }
  12.    const handleSub = (id: number) => {
  13.       setGoods(goods.map(item => item.id === id ? { ...item, count: item.count - 1 } : item));
  14.    }
  15.    const total = () => {
  16.       console.log('total');
  17.       //例如很复杂的计算逻辑
  18.       return goods.reduce((total, item) => total + item.price * item.count, 0)
  19.    }
  20.    return (
  21.       <div>
  22.          <h1>父组件</h1>
  23.          <input type="text" value={search} onChange={(e) => setSearch(e.target.value)} />
  24.          <table border={1} cellPadding={5} cellSpacing={0}>
  25.             <thead>
  26.                <tr>
  27.                   <th>商品名称</th>
  28.                   <th>商品价格</th>
  29.                   <th>商品数量</th>
  30.                </tr>
  31.             </thead>
  32.             <tbody>
  33.                {goods.map(item => <tr key={item.id}>
  34.                   <td>{item.name}</td>
  35.                   <td>{item.price * item.count}</td>
  36.                   <td>
  37.                      <button onClick={() => handleAdd(item.id)}>+</button>
  38.                      <span>{item.count}</span>
  39.                      <button onClick={() => handleSub(item.id)}>-</button>
  40.                   </td>
  41.                </tr>)}
  42.             </tbody>
  43.          </table>
  44.          <h2>总价:{total()}</h2>
  45.       </div>
  46.    );
  47. }
  48. export default App;
复制代码
当我们利用 useMemo 缓存后,只有 goods 发生变革时, total 才会重新盘算, 而 search 发生变革时, total 不会重新盘算。
  1. import React, { useMemo, useState } from 'react';
  2. function App() {
  3.    const [search, setSearch] = useState('');
  4.    const [goods, setGoods] = useState([
  5.       { id: 1, name: '苹果', price: 10, count: 1 },
  6.       { id: 2, name: '香蕉', price: 20, count: 1 },
  7.       { id: 3, name: '橘子', price: 30, count: 1 },
  8.    ]);
  9.    const handleAdd = (id: number) => {
  10.       setGoods(goods.map(item => item.id === id ? { ...item, count: item.count + 1 } : item));
  11.    }
  12.    const handleSub = (id: number) => {
  13.       setGoods(goods.map(item => item.id === id ? { ...item, count: item.count - 1 } : item));
  14.    }
  15.    const total = useMemo(() => {
  16.       console.log('total');
  17.       return  goods.reduce((total, item) => total + item.price * item.count, 0)
  18.    }, [goods]);
  19.    return (
  20.       <div>
  21.          <h1>父组件</h1>
  22.          <input type="text" value={search} onChange={(e) => setSearch(e.target.value)} />
  23.          <table border={1} cellPadding={5} cellSpacing={0}>
  24.             <thead>
  25.                <tr>
  26.                   <th>商品名称</th>
  27.                   <th>商品价格</th>
  28.                   <th>商品数量</th>
  29.                </tr>
  30.             </thead>
  31.             <tbody>
  32.                {goods.map(item => <tr key={item.id}>
  33.                   <td>{item.name}</td>
  34.                   <td>{item.price * item.count}</td>
  35.                   <td>
  36.                      <button onClick={() => handleAdd(item.id)}>+</button>
  37.                      <span>{item.count}</span>
  38.                      <button onClick={() => handleSub(item.id)}>-</button>
  39.                   </td>
  40.                </tr>)}
  41.             </tbody>
  42.          </table>
  43.          <h2>总价:{total}</h2>
  44.       </div>
  45.    );
  46. }
  47. export default App;
复制代码
useMemo 实验时机(依赖项)


  • 如果依赖项是个空数组,那么 useMemo 的回调函数会实验一次
  • 指定依赖项,当依赖项发生变革时, useMemo 的回调函数会实验
  • 不指定依赖项,不保举这么用,由于每次渲染和更新都会实验
useMemo 总结


  • 利用场景

    • 当须要缓存复杂盘算效果时
    • 当须要制止不须要的重新盘算时
    • 当盘算逻辑复杂且耗时时

  • 优点

    • 通过影象化制止不须要的重新盘算
    • 进步应用性能
    • 镌汰资源斲丧

  • 注意事项

    • 不要过分利用,只在确实须要优化的组件上利用
    • 如果依赖项常常变革,useMemo 的效果会大打扣头
    • 如果盘算逻辑简朴,利用 useMemo 的开销大概比重新盘算还大


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表