当前位置: 首页 > news >正文

邯郸市网络科技有限公司seo优化运营专员

邯郸市网络科技有限公司,seo优化运营专员,潍坊网站建设优化排名,广西南宁网站空间您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~ 前言 一个很常见的场景,React中父组件和子组件在一起,子组件不依赖于父组件任何数据,但是会一起发生变化。 在探究原…

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

前言

一个很常见的场景,React中父组件和子组件在一起,子组件不依赖于父组件任何数据,但是会一起发生变化。

在探究原理之前,先回忆一下,React中的Diff算法会将更新前后的两棵虚拟DOM树做对比,但这并不会决定组件是否更新,只会决定是否要复用老的节点。

举个简单的例子:

import { useState } from 'react';const Child = () => {console.log('child render');return null;
};const App = () => {const [name, setName] = useState(1);return (<div onClick={() => setName(2)}><Child /></div>);
};

Child组件没有接收来自父组件的值,每次点击父组件元素让name更新,Child组件会更新吗?答案是会的,你一定会好奇,子组件没有接收任何的props,为什么也会更新呢?

首先,父组件经过了Diff阶段,会判断Child组件是否发生变化,在本案例中Child内部的元素结构和状态无任何变化,React还会对比Child组件前后的props是否相同,在本案例中,前后props不相同。

说到这里,你一定忍不住了,我都没传props,为啥不相同?原因是React内部对于props的对比只进行了浅层比较,通过 !== 来判断,这样即使没传props,每次生成的props对象都是新的指针,即使为空,也会生成不同的props空对象,就像这样:

const oldProps = current.memoizedProps; // 更新前老的propsconst newProps = workInProgress.pendingProps; // 待比较更新后的propsif (oldProps !== newProps) {didReceiveUpdate = true; // 标记为发生变化,需要更新
}

那有什么方法可以避免这样的无效更新呢?一共有三种方案。

  1. 使用React.memo,可以指定在Diff时对于被memo包裹的组件只做浅层比较;
  2. 使用React.useMemoReact.useCallback来包住子组件,让每次更新子组件都为同一个JSX对象,这也props的比较就会相同;
  3. 将子组件作为children来传递;

React.memo

对于方案1,React.memo的原理其实来源于源码中的shallowEqual函数,该函数会接收两个对象,分别对应老的props和新的props,一共有四种比较策略,如果四种策略都通过,则判定新旧为同一个对象,不做更新,复用老的节点。

  1. 判断两者是否为同一对象,不是同一对象则返回false;
  2. 判断两者的值不为object或为null,则返回false;
  3. 对比两者key的数量,不一致则返回false;
  4. 对比两者key的值是否相同,不一致则返回false;

源码如下:

 function shallowEqual(objA: mixed, objB: mixed): boolean {// 一样的对象返回trueif (Object.is(objA, objB)) {return true;}// 不是对象或者为null返回falseif (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {return false;}const keysA = Object.keys(objA);const keysB = Object.keys(objB);// key数量不同返回falseif (keysA.length !== keysB.length) {return false;}// 对应key的值不相同返回falsefor (let i = 0; i < keysA.length; i++) {if (!hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {return false;}}return true;
}

可以看到浅比较props的实现原理很简单,对应着上述四种策略。

React.useMemo & React.useCallBack

对于方案2,如果你不了解React.useMemoReact.useCallback,没有关系,先看一下这段代码块:

import { useMemo } from 'react';const Child = () => {console.log('child render');return null;
};const App = () => {const [name, setName] = useState(1);const child = useMemo(() => <Child />, []);return <div onClick={() => setName(2)}>{child}</div>;
};

React.useMemo接收两个参数,第一个参数为返回值,第二个参数为依赖项,当依赖项数组中的值发生变化,则返回值会重新计算,也就是说第二个依赖项传空数组,则依赖项永远都不会发生变化,则Child组件经过React.useMemo包裹后一直不会被React去计算Diff,就实现了父组件更新,子组件不触发更新。

但对于React.useMemo的使用,如果传给了子组件的值,但是未声明依赖项,会导致子组件一直不发生变化,就像这样:

import { useMemo } from 'react';const Child = ({ name }) => {console.log('child render');return name;
};const App = () => {const [name, setName] = useState(1);const child = useMemo(() => <Child name={name} />, []);return <div onClick={() => setName(2)}>{child}</div>;
};

像这种情况,父组件将name传给了子组件,但是由于子组件未声明name为改变依赖项,因此当name发生变化,子组件依然会永远返回初始值1,因此对于React.useMemo的缓存策略在优化时也需要充分考虑意外事故发生。

向上提炼 & 向下移动

对于方案3,可以简单理解成向上提炼和向下移动state,先看一个案例:

const App = () => {const [color, setColor] = useState('red');return (<div><input value={color} onChange={(e) => setColor(e.target.value)} /><p style={{ color }}>Hello, world!</p><Child /></div>);
};

InputonChange事件是一个频繁触发的颜色指示器,一秒会触发上百次,而Child组件是一个固定渲染不依赖父组件状态的子组件,如何通过状态向下移动的方式来避免Child组件被渲染呢?

const App = () => {return (<div><Form /><Child /></div>);
};

我们只需要将这段性能消耗大的代码抽离到单独的一个Form组件中,同时把color状态单独交给Form组件去管理,这样App父组件一直没有发生重渲染,Child子组件也不会被影响,只有Form子组件在单独发生交互,这种方案更像是一个状态下移 + 隔离

还有一种解法就是状态提升,我们可以把这段性能消耗严重的代码同样单独封装成一个组件,将Child子组件的内容传递给Form子组件,就像这样:

const Form = ({ children }) => {const [color, setColor] = useState('red');return (<div style={{ color }}><input value={color} onChange={(e) => setColor(e.target.value)} />{children}</div>);
};const App = () => {return (<div><Form><p>Hello, world</p><Child /></Form></div>);
};

其实思路是和状态向下提升是一样的,把性能消耗严重的一部分单独抽离到一个组件中,将相对不期望被影响的一部分通过特定形式渲染,因此Child子组件在这种情况也不会被重新渲染。

结尾

本文主要记录了博主在日常开发用到比较多的三种优化策略,微笑的细节差带来的优化提升手段,希望对你有帮助哦~

如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

http://www.yidumall.com/news/70396.html

相关文章:

  • 自己做的网站页面错误最全磁力搜索引擎
  • wordpress添加侧边栏的轮播图优化近义词
  • 拉萨北京网站建设免费站长工具
  • 北京二级建造师查询系统seo工具软件
  • 政府网站开发计划书软文范例大全200字
  • 企业网站备案 名称网站宣传方式有哪些
  • 网站的论坛怎么做互联网营销师是做什么的
  • 广州手机网站定制咨询凤凰网全国疫情实时动态
  • 苏州网页制作培训班seo的基本步骤
  • 网站如何防盗链请简述网络营销的特点
  • 郑州做网站哪个公司好百度竞价优化排名
  • 重庆专业建网站重庆网站推广联系方式
  • 云端网站建设软文广告图片
  • 百度怎么收录我的网站湖南企业seo优化报价
  • 黄埔网站建设国产搜什么关键词最好看
  • 加强网站备案管理专项行动最近的新闻热点时事
  • 北京住房和城乡建设局门户网站什么是引流推广
  • 专做装修的网站谷歌代运营
  • 做代账的网站天眼查询个人
  • 搜索引擎技巧惠州市seo广告优化营销工具
  • 小型企业网站开发公司网页设计个人主页
  • 建网站赚钱合肥百度竞价推广代理公司
  • 北京建设信源网站 怎么打不开外贸seo推广公司
  • 无锡做公司网站多少钱定制网站制作公司
  • 网站类型是什么意思舆情信息在哪里找
  • 建筑资料网站大全网站的推广方法有哪些
  • 马鞍山做网站公司排名合肥网站seo推广
  • 网站建设开发能力很强的企业解释seo网站推广
  • 上海市城乡建设委员会网站每日新闻简报
  • 制作大型网站开发怎么在百度上做广告