在每个地方都应该添加 memo 吗?

在这里插入图片描述

文章概叙

本文主要讲的是React中memo的使用,以及考虑是否使用memo的判断依据

memo介绍

memo 允许你的组件在 props 没有改变的情况下跳过重新渲染。

在使用memo将组件包装起来之后,我们可以‍获得该组件的一个 记忆化 版本。通常情况下,只要该组件的 props 没有改变,这个记忆化版本就不会在其父组件重新渲染时重新渲染。

也正是因为如此,在开发过程中,我们都会说“用memo来缓存组件,跳过组件的重复渲染”等说法,此时所说的memo就是该API,当我们传入的props没有变化(需要注意的是,数组等对象,引用地址不能变化),组件就不会被重新渲染了,就能适当的减少我们的开支~

简单示例

下面的例子中,父组件包括了一个循环的定时器,以及一个子组件,不过对子组件传入的是一个固定的值,代码如下

//父组件的代码
import React, { useEffect, useState } from "react";
import "./App.css";
import MemoComponent from "./components/MemoComponent";function App() {
  const [date, setDate] = useState(0);
  useEffect(() => {
    setInterval(() => {
      setDate(+new Date());
    }, 1000);
  }, []);
  return (
    <div className="App">
      <p>{date}</p>
      <MemoComponent num_array={1} />
    </div>
  );
}export default App;
//子组件的代码
export default (props: any) => {
  console.log("子组件是否刷新");
  return (
    <>
      <div>这个是其中一个子组件</div>
    </>
  );
};

而由于父组件的一直刷新,所以我们的子组件也会跟着被重新渲染。

此时,我们在考虑如何优化我们的组件时,方向就很明显了,就是当计时器一直刷新的时候,我们的子组件并不需要一直刷新。

那么这时候我们就可以使用memo来跳过子组件的重新渲染。
在这里插入图片描述

memo语法

memo(Component, arePropsEqual)

  • Component
    我们需要进行记忆化的组件,react并不会对其做任何的修改,只是做一个高阶组件的处理,添加完自己的操作后返回给你。

  • arePropsEqual
    可选参数,接受两个参数:组件的前一个 props 和新的 props。一般情况我们不需要去管他,直接忽略他,因为React会使用Object.js去判断前后props是否相同,如果我们手动设置了,会很容易出啥错。

使用memo

理解了memo的语法之后,我们可以在我们的子组件中,使用memo将组件包含起来,使其跳过重复渲染,代码如下

//子组件的代码
import { memo } from "react";export default memo((props: any) => {
  console.log("子组件是否刷新");
  return (
    <>
      <div>这个是其中一个子组件</div>
    </>
  );
});


此时,由于我们使用memo,子组件避免了无用的重复渲染,所以控制台就不会一直显示子组件被渲染的情况了。
在这里插入图片描述

memo的地址判断

上章提及到,memo会判断我们传入的props是否一样,但当我们传入一个数组(或者对象)的时候,我们会发现我们的页面中,子组件又被重新渲染了。

 //父组件代码
  <MemoComponent num_array={[1,2,3,4]} />

这是因为,当我们使用数组或者是对象的时候,由于使用的Object.js在判断对象是否一致的时候,会判断引用地址,所以我们看起来值一样,但是实际上不是同一个(参考js数据类型)。

此时我们可以使用useState来保证数组不被重新赋值。

//父组件的代码
import React, { useEffect, useState } from "react";
import "./App.css";
import MemoComponent from "./components/MemoComponent";function App() {
  const [date, setDate] = useState(0);
  const [numArray,setNumArray]=useState([1,2,3,4,5])
  useEffect(() => {
    setInterval(() => {
      setDate(+new Date());
    }, 1000);
  }, []);
  return (
    <div className="App">
      <p>{date}</p>
      <MemoComponent numArray />
    </div>
  );
}export default App;

使用了useState之后,由于我们的numArray的每次都是一样的值,一样的地址,子组件就不会被重新刷新了。

所以当你使用memo之后,发现你的项目并没有按照你的预想走的时候,可以检查下你的组件的props。

滥用memo

既然memo有那么多的好处,那为什么我们的项目中没有出现所有的组件都用memo包起来呢?

下面的例子中,我们使用了memo包括了10个组件,且在5s后,我们的父组件会刷新一次页面,而子组件的代码不变。

//父组件代码
import React, { useEffect, useState } from "react";
import "./App.css";
import MemoComponent from "./components/MemoComponent";function App() {
  const [date, setDate] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setDate(+new Date());
    }, 5000);
  }, []);
  return (
    <div className="App">
      <p>{date}</p>
      {new Array(10).fill(1).map((v) => (
        <MemoComponent />
      ))}
    </div>
  );
}export default App;


下面是使用了memo处理组件的情况下,大概理解为当计时器触发之后,我们的页面花了14ms来重新渲染我们的页面(3915-3901)

在这里插入图片描述

但是当我们去掉了代码中的memo之后,我们发现,计时器触发之后,我们的页面只需要花费11ms(3388-3377)的时间来渲染。
在这里插入图片描述

你以为我会跟借此跟你说,当给每一个组件都添加了memo之后,由于props的判断会导致页面渲染更多时间吗?​

官网上提及到下面这段话

只有当你的组件经常使用完全相同的 props 重新渲染时,并且其重新渲染逻辑是非常昂贵的,使用 memo
优化才有价值。如果你的组件重新渲染时没有明显的延迟,那么 memo 就不必要了。请记住,如果传递给组件的 props
始终不同,例如在渲染期间传递对象或普通函数,则 memo 是完全无用的。这就是为什么你通常需要在 memo 中同时使用 useMemo 和
useCallback

众所周知,我们的react是通过判断props是否发生变化的来判定是否重新渲染组件的,那么我们可以理解,当我们用一个很复杂的props来节省一个很简单的子组件的时候,我们是否就已经失败了呢?

因为我们的react需要先去判断props是否相同,而当花费了30ms的时间在判断props后,结果只是缓存了一行文字…你猜react会不会气抖冷?

毕竟你去吃饭,老板弄了一道高数题,说解出来了,答案就是wifi密码,你千辛万苦解出来,发现老板家的wifi只有1k/s,不单单打扰你跟小姐姐聊天,还用你手机挖矿,你就知道什么感觉了。

至于React的memo是否会占用多一些空间缓存的,由于本人没有具体的demo,所以推荐大家看下github上的答复,就不验证了​​

在这里插入图片描述

一个前端博客,希望能帮到小白们

公众号求关注~

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将通过UART串口通信获得的汉字点阵转换为汉字并显示在Memo中,可以按照以下步骤进行操作: 1. 通过UART串口通信获取汉字点阵数据,可以使用C++ Builder自带的TComPort组件或第三方的串口通信库,如TurboPower Async Professional等。 2. 将获取到的汉字点阵数据转换为汉字,可以使用Windows API函数GetFontData和CreateFontIndirect来实现。具体步骤如下: a. 使用GetFontData函数获取汉字点阵数据,需要指定字体名称、字体大小和字符编码等参数。 b. 将获取到的点阵数据转换为16进制字符串。 c. 将16进制字符串转换为汉字,可以使用Windows API函数MultiByteToWideChar和WideCharToMultiByte来实现。 3. 将转换后的汉字显示在Memo中,可以使用Memo的Lines属性来添加文本。 下面是一个示例代码: ```c++ #include <Windows.h> #include <Vcl.ComCtrls.hpp> // 获取汉字点阵数据 bool GetFontData(const wchar_t* fontName, int fontSize, wchar_t ch, std::vector<BYTE>& data) { HDC hdc = GetDC(NULL); HFONT hFont = CreateFontIndirect(&LOGFONT{ fontSize * -GetDeviceCaps(hdc, LOGPIXELSY) / 72, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, fontName }); SelectObject(hdc, hFont); DWORD size = GetFontData(hdc, 0, 0, NULL, 0); std::vector<BYTE> buffer(size); DWORD result = GetFontData(hdc, 0, 0, &buffer[0], size); DeleteObject(hFont); ReleaseDC(NULL, hdc); if (result == GDI_ERROR) return false; int glyphIndex = GetGlyphIndicesW(hdc, &ch, 1, NULL, 0); if (glyphIndex == GDI_ERROR) return false; data.resize(size); result = GetFontData(hdc, 0, glyphIndex, &data[0], size); return result != GDI_ERROR; } // 将点阵数据转换为16进制字符串 std::string HexString(const BYTE* data, size_t size) { std::string result(size * 2, '\0'); for (size_t i = 0; i < size; ++i) sprintf_s(&result[i * 2], 3, "%02X", data[i]); return result; } // 将16进制字符串转换为汉字 std::wstring HexToWString(const std::string& hex) { std::wstring result; for (size_t i = 0; i < hex.size(); i += 4) { wchar_t ch = 0; swscanf_s(hex.c_str() + i, L"%04X", &ch); result += ch; } return result; } // 将汉字点阵数据转换为汉字并显示在Memo中 void DisplayChineseCharacter(const wchar_t* fontName, int fontSize, BYTE* data, size_t size, TRichEdit* memo) { std::string hex = HexString(data, size); std::wstring text = HexToWString(hex); memo->Lines->Add(text.c_str()); } // 示例用法 void ExampleUsage() { // 假设从串口中获取到一个字体为"宋体",大小为16的汉字点阵数据,编码为"你"(0xC4E3) wchar_t fontName[] = L"宋体"; int fontSize = 16; wchar_t ch = L'你'; std::vector<BYTE> data; if (GetFontData(fontName, fontSize, ch, data)) { DisplayChineseCharacter(fontName, fontSize, &data[0], data.size(), Memo1); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值