我的编程空间,编程开发者的网络收藏夹
学习永远不晚

一文详解React渲染优化之useImmer

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

一文详解React渲染优化之useImmer

从一个例子开始

import { FC, useState, useEffect } from 'react';

const App: FC = () => {
  const [list, setList] = useState({ a: 1 });

  useEffect(() => {
    setList({ a: 1 });
  }, []);

  console.log('测试');

  return (
    <>
      <h1>Hello Web3 React {list.a}</h1>
    </>
  );
};

export default App;
  • 看控制台输出结果

  • 因为list是引用对象,虽然内部的值相同,但引用地址变化了,因此react认为state发生了变化,因此触发了渲染,这也联想到如果我们传递props时为对象或数组时,会造成我们非期望渲染的缘由,那我们该如何解决这个问题呢?
  • 在此之前,先介绍一个react渲染检查工具 why-did-you-render

渲染检查工具

why-did-you-render, 可以在开发时,帮你检测无意义的渲染

  • 安装 yarn add @welldone-software/why-did-you-render -D
  • class="lazy" data-src下创建 wdyr.tsx
/// <reference types="@welldone-software/why-did-you-render" />
import React from 'react';

if (process.env.NODE_ENV === 'development') {
  // eslint-disable-next-line
  const whyDidYouRender = require('@welldone-software/why-did-you-render');
  whyDidYouRender(React, {
    onlyLogs: true,
    titleColor: 'green',
    diffNameColor: 'darkturquoise',
    trackHooks: true,
    trackAllPureComponents: true,
  });
}
  • 在入口文件 index.tsx 引入

  •  4.上面的例子,输出结果,显示无意义渲染

要解决这个问题,需要我们使用到Immer

Immer 与 UseImmer

  • 不可变数据:不可变数据的特点就是产出地址不同的对象引用,同时尽可能保留没必要更新的属性或者子属性,这样在你的组件树中如果有数据的其他属性或者子熟悉的依赖存在的话,可以避免一些rerender
  • immutable:不改变原数据,将变化的部分与不变的部分组成一个新的数据对象**
  • Immer:简化了不可变数据结构的处理,与immutable代码简单,去掉树的压缩,使用proxy代理,组合新的树
    • immer 可以在需要使用不可变数据结构的任何上下文中使用,例如:React state、Redux等
    • 不可变的数据结构允许(高效)的变化检测:如果对象的引用没有改变,那么对象本身也没有改变。此外,它使克隆对象相对便宜:数据树的未更改部分不需要复制,并且在内存中与相同状态的旧版本共享

  • 利用 produce 函数,它将我们要更改的 state 作为第一个参数,对于第二个参数,我们传递一个名为 recipe 的函数,该函数传递一个 draft 参数,我们可以对其应用直接的 mutations。一旦 recipe 执行完成,这些 mutations 被记录并用于产生下一个状态。 produce 将负责所有必要的复制,并通过冻结数据来防止未来的意外修改

Immer是如何工作的?

  • 使用 Immer,您会将所有更改应用到临时 draft,它是 currentState 的代理。一旦你完成了所有的 mutations,Immer 将根据对 draft state 的 mutations 生成 nextState。这意味着您可以通过简单地修改数据来与数据交互,同时保留不可变数据的所有好处

  • 使用 Immer 就像拥有一个私人助理。助手拿一封信(当前状态)并给您一份副本(草稿)以记录更改。完成后,助手将接受您的草稿并为您生成真正不变的最终字母(下一个状态)

Immer优点

  • 深度更新轻而易举
  • 开箱即用的结构共享
  • 开箱即用的对象冻结
  • 代码简洁
  • 小巧:3KB gzip

使用

state + Immer

useImmer

  • 替代 state

  • 本文开始的例子使用 useImmer
import { FC, useEffect } from 'react';
import { useImmer } from '@hooks/useImmer';

const App: FC = () => {
  const [list, setList] = useImmer({ a: 1 });

  useEffect(() => {
    // setList({ a: 1 });
    setList(draft => {
      draft.a = 1;
    });
  }, []);

  console.log('测试');

  return (
    <>
      <h1>Hello Web3 React {list.a}</h1>
    </>
  );
};

export default App;

观察控制台,发现已经没有无意义渲染的提示了,It's wonderful!

  • 注意:Immer 并没有 Immutable 解决的那么彻底,我们不能直接给draft赋值,而在draft上操作是极好的
useEffect(() => { 
  // setList({ a: 1 });
  setList(draft => {
    draft.a = 1;
  }); 
},[]);

自己动手实现hooks-useImmer

import { useCallback, useState } from 'react';
import { produce, Draft, freeze } from 'immer';


export type DraftFunction<S> = (draft: Draft<S>) => void;
export type Updater<S> = (arg: S | DraftFunction<S>) => void;
export type ImmerHook<S> = [S, Updater<S>];
export function useImmer<S = any>(initialState: S | (() => S)): ImmerHook<S>;


export function useImmer<T>(initialState: T) {
  // const [state, setState] = useState(initialState);
  // 冻结 state,第二参数 true,表示深度冻结,对象不能修改了
  const [value, updateValue] = useState(() =>
    freeze(typeof initialState === 'function' ? initialState() : initialState, true)
  );

  // 使用 useCallback,放置组件间传递,产生句柄
  return [
    value,
    useCallback((updater: Updater<T>) => {
      if (typeof updater === 'function') {
        updateValue(produce(updater));
      } else {
        updateValue(freeze(updater));
      }
    }, []),
  ];
}

以上就是一文详解React渲染优化之useImmer的详细内容,更多关于React渲染优化useImmer的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

一文详解React渲染优化之useImmer

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

一文详解React渲染优化之useImmer

在React日常开发中,我们常常被重复渲染或无意义渲染所折磨,穷尽脑汁,做各种优化:memo、useMemo、useCallback、immutable等,本文主要讲述immutable的简约版Immer,感兴趣的同学可以一起来学习
2023-05-19

ReactQuery 渲染优化示例详解

这篇文章主要为大家介绍了ReactQuery 渲染优化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

React性能优化之非必要的渲染问题如何解决

这篇“React性能优化之非必要的渲染问题如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“React性能优化之非必要的
2023-07-02

JS技巧Canvas性能优化脏矩形渲染实例详解

这篇文章主要为大家介绍了JS技巧Canvas性能优化脏矩形渲染实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-16

详解cesium实现大批量POI点位聚合渲染优化方案

这篇文章主要为大家介绍了cesium实现大批量POI点位聚合渲染优化方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-19

解析Android开发优化之:对界面UI的优化详解(一)

通常,在这个页面中会用到很多控件,控件会用到很多的资源。Android系统本身有很多的资源,包括各种各样的字符串、图片、动画、样式和布局等等,这些都可以在应用程序中直接使用。这样做的好处很多,既可以减少内存的使用,又可以减少部分工作量,也可
2022-06-06

React高阶组件优化文件结构流程详解

高阶组件就是接受一个组件作为参数并返回一个新组件(功能增强的组件)的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意,本文给大家分享React高阶组件HOC使用小结,一起看看吧
2023-01-29

一文详解MySQL—Join的使用优化

目录mysql JOIN类型MySQL JOIN 算法Nested-Loop Join 算法执行流程工作原理时间复杂度分析block Nested-Loop Join 算法执行流程工作原理时间复杂度分析Hash Join 算法执行流程bui
2023-04-21

MySQL性能优化之一条SQL在MySQL中执行的过程详解

天天和数据库打交道,一天能写上几十条SQL语句,但你知道系统是如何和数据库交互的吗?下面这篇文章主要给大家介绍了关于MySQL性能优化之一条SQL在MySQL中执行的过程的相关资料,需要的朋友可以参考下
2023-02-02

一文详解如何使用线程池来优化我们的应用程序

线程池是一种工具,但并不是适用于所有场景。在使用线程池时,我们需要根据应用程序的性质、计算资源的可用性和应用程序的需求进行适当的配置。本文主要介绍了如何使用线程池来优化我们的应用程序,需要的可以参考一下
2023-05-14

一文详解 CMS 支付集成:优化医疗费用支付流程,提升患者就医体验

CMS 支付集成是指医疗机构与 CMS(医保中心)系统进行连接,实现患者医疗费用自动结算,从而简化支付流程、提升就医体验。本文将详细介绍 CMS 支付集成的好处、实施步骤、常见问题解答等,帮助医疗机构更好理解并实施 CMS 支付集成。
一文详解 CMS 支付集成:优化医疗费用支付流程,提升患者就医体验
2024-02-09

编程热搜

目录