惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
美团技术团队
H
Hacker News: Front Page
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tenable Blog
Simon Willison's Weblog
Simon Willison's Weblog
T
The Exploit Database - CXSecurity.com
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
C
CXSECURITY Database RSS Feed - CXSecurity.com
Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
About on SuperTechFans
F
Fortinet All Blogs
量子位
GbyAI
GbyAI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Hacker News
The Hacker News
AWS News Blog
AWS News Blog
Forbes - Security
Forbes - Security
Help Net Security
Help Net Security
I
InfoQ
有赞技术团队
有赞技术团队
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Secure Thoughts
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Webroot Blog
Webroot Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
C
Check Point Blog
T
Troy Hunt's Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Latest news
Latest news
P
Proofpoint News Feed
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Martin Fowler
Martin Fowler
雷峰网
雷峰网
博客园 - Franky
L
LangChain Blog
罗磊的独立博客
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
D
Docker
G
GRAHAM CLULEY
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

时间的朋友

Windows 命令行密码重置 Anaconda安装 typescript 注解解读1 Konvajs Shape加载自定义图片 sshpass 使用 why-is-node-running webgl笔记 SharedArrayBuffer is not defined blender 常用快捷键 vue -- v3.4commit提交记录2 vue2 升级vue3报错问题整理 着色器 expressjs 源码 hyper-V arch linux 网络配置 element input数字格式化 three 拼接货架 WebAudio笔记 Windows nginx重启bat脚本 vue -- v3.4commit提交记录 URI malformed vue3 -- Class 对象在组件中使用范例 | 时间的朋友 ruby 安装和升级 element-plus 老版本cascader使用卡死问题 vue3 内置Transition组件 前端memo的实现 Vue -- vue-class-component源码 linux 优化脚本 typescript 装饰器 microbundle 源码 WSL2问题解决WslRegisterDistribution failed with error: 0x800701bc vue -- vue3利用createVNode函数,建立命令式调用组件 SSH connection failed: connect ECONNREFUSED 请求中获取浏览器推荐语言 flutter 生命周期 双向链表 堆和栈 EventSource 单向链表 简易的事件监听EventBus fork的仓库更新分支 forwardRef 定义的组件添加静态属性 js 获取滚动元素 canvas requestAnimationFrame画一个clock mousedown event中保持input的focus状态 vue -- @vue/compiler-core整体逻辑 IOS端h5 fixed滚动问题 vue -- compile结果代码解读 vue -- transformElement源码 Vue -- 内置指令源码 vue3 -- @vue/compiler-sfc compileScript源码 浏览器工作原理 对比2个版本号的方法 vite 向entry html中注入代码 小程序 -- 内部使用webview绑定微信公众号openId github coding同步action 小程序 -- 微信外部浏览器或者链接打开方式整理 MSE -- MediaSource 的前端使用 rollup 打包vue2组件 常用工具函数整理 Benchmark.js 使用 import-html-entry js沙箱实现源码 import-html-entry 笔记 axios core源码 国内开源镜像网站 nuxt -- docker-compose进行部署 vue -- provide和inject原理 vue -- hoistStatic原理 jenkins 配置模板代码 vue -- compileTemplate原理 小程序开发问题整理 webpack-dev-server proxy代理模块 vite 代理中更改请求头问题 Async.js flutter 问题整理 比较两个数组的不同项 ms源码解析 浏览器同源策略 前端缓存笔记 webpack5 schema-utils tsc 和 babel 编译typescript区别 typescript 学习笔记 esbuild api整理 Webpack Chain 源码 deepmerge库源码解读 Vue 自定义指令的执行机制 linux 问题整理 webpack5学习笔记 elementui form多表单验证 Webpack5 -- Assest Module vue -- 实现MenuTree组件 Vue -- VFor的编译处理 vue -- 使用中问题整理 算法基础知识 浏览器环境检测函数整理 yarn 问题搜集 c++笔记 webpack 模块加载原理 webpack 模块加载原理(二) Zero Width Characters slate.js API整理
React Rerender重绘原理
2022-05-08 · via 时间的朋友

react rerender原理 🔗

react中组件重绘是一个不可避免的问题,因为react中组件的更新方式就是旧组件销毁,新组件替代旧组件的形式。而且react组件中以树的形式进行构建,必然带来的就是父组件更新,其所有的子组件都会更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 父组件
function ListComp() {
  const [list, setList] = useState([
    {
      id: 1,
      value: "",
    },
    {
      id: 2,
      value: "",
    },
    {
      id: 3,
      value: "",
    },
  ]);

  return (
    <div>
      <div>{JSON.stringify(list)}</div>

      <div>
        {list.map((item, idx) => (
          <Item
            key={idx}
            {...item}
            onChange={(id: number, value: any) => {
              setList(
                list.map((item) => {
                  if (item.id === id) {
                    item.value = value;
                  }
                  return item;
                })
              );
            }}
          ></Item>
        ))}
      </div>
    </div>
  );
}

// 子组件
function Item({ id, value, onChange }) {
  return (
    <div>
      <h3>{id}</h3>
      <input
        type="text"
        value={value}
        onChange={(e) => onChange(id, e.target.value)}
      />
    </div>
  );
}

在只输入一个输入框的同时,其他子组件都在重新渲染

同样只更新父组件的同时,子组件也会更新

当组件的状态发生变化时,组件及其子组件都会rerender

如果不想子组件发生不必要的render,使用memo包裹一下组件

1
const Item = memo(() => <div>Item</div>)

可以看到父组件更新后,子组件不会再发生rerender

我重新包裹一下我们的子组件Item

1
const ItemWrapper = memo(Item)

子组件还是会发生不必要的rerender

当组件使用memo包裹后还会发生rerender,说明组件又props发生了变化

排查后就是onChange属性发生了变化, 每次父组件rerender后子组件都会重新生产一个onChange事件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
onChange={(id: number, value: any) => {
  setList(
    list.map((item) => {
      if (item.id === id) {
        item.value = value;
      }
      return item;
    })
  );
}}

使用useCallback对属性进行缓存,useCallback会生成一个函数缓存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  const onChange = useCallback((id: any, value: any) => {
    setList((preList) =>
      preList.map((item) => {
        if (item.id === id) {
          item.value = value;
        }
        return item;
      })
    );
  }, []);

最终代码 🔗

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const Item: React.FC<{ id: any; value: any; onChange: any }> = memo(({ id, value, onChange }: any) => {
  return (
    <div
      style={{
        width: "200px",
        display: "inline-block",
      }}
    >
      <h3>{id}</h3>
      <input
        type="text"
        value={value}
        onChange={(e) => onChange(id, e.target.value)}
      />
    </div>
  );
});

const Parent = () => {
  const [items, setItems] = useState([
    { value: "", id: 1 },
    { value: "", id: 2 },
    { value: "", id: 3 },
  ]);
  const onChange = useCallback((id: any, value: any) => {
    setItems(
      items => items.map((item) => {
        if(item.id === id) {
          item.value = value
        }
        return item;
      })
    );
  }, []);

  return (
    <div style={{ padding: "20px" }}>
      <div>{JSON.stringify(items)}</div>
      {items.map((item, index) => (
        <Item key={index} id={item.id} value={item.value} onChange={onChange} />
      ))}
    </div>
  );
};

https://alexsidorenko.com/blog/react-list-rerender/