你可能没有关注过的 React 性能优化,0基础学Web前端

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

先说两句


关于我今天想写的内容,大部分你其实都可以在React官方文档上学习到。那为什么我还是想写?因为作为一个写了差不多有三年的React的人,我居然没有正儿八经的通读过官方文档,我想告诉的可能是和我类似的人吧,同时也补充一些我自己的理解和看法。

问你几个问题


性能优化这个问题啊,真的是永远都逃不了,是个面试官都要问几句,不过说实话不知道是React做的太好了,还是我做的项目都太基础了,基本没遇到过什么性能问题,导致我在很长一段时间内根本不知道 React 还有很多跟性能优化有关的 API。

先来看个代码,我直接在一个文件里定义多个组件方便大家观看,正式编写代码的时候一个文件就是一个组件。

import React from ‘react’;

class Test extends React.Component {

componentDidUpdate() {

console.log(‘Test componentDidUpdate’);

}

render() {

return 

;

}

}

export default class App extends React.Component {

constructor(props) {

super(props);

this.state = { count: 0 };

this.handleClick = this.handleClick.bind(this);

}

handleClick() {

this.setState((state) => ({

count: state.count + 1,

}));

}

handleTestClick() {}

render() {

return (

{this.state.count}
click

);

}

}

这代码没什么好说的,每次点击click更新state,我现在问几个问题,你先思考一下~

  1. 每次点击click的时候,Test组件会打印Test componentDidUpdate吗?

  2. 如果我把Test组件的React.Component替换为React.PureComponent,结果与上面一样吗?如果不一样,为什么?

  3. 如果我修改这一行代码<Test onClick={this.handleTestClick} /><Test onClick={() => {}} />结果又如何?

shouldComponentUpdate


好像所有的内容都要从这个东西说起,shouldComponentUpdate作为React生命周期的一部分,大多数React开发者至少还是听说过它的,简单来说在这个函数中返回一个布尔值,React会根据这个布尔值来判断组件是否需要重新渲染。

shouldComponentUpdate接收两个参数,一个是更新后的props,一个是更新后的state,可以通过比较两个propsstate来决定是否需要重新渲染组件。

import React from ‘react’;

class Test extends React.Component {

componentDidUpdate() {

console.log(‘Test componentDidUpdate’);

}

// 每次点击 click 都会打印 Test componentDidUpdate

// 添加这个函数后当 count 没有变化时不会打印 Test componentDidUpdate

shouldComponentUpdate(nextProps) {

if (this.props.count === nextProps.count) {

return false;

}

return true;

}

render() {

return 

;

}

}

export default class App extends React.Component {

constructor(props) {

super(props);

this.state = { count: 0 };

this.handleClick = this.handleClick.bind(this);

}

handleClick() {

this.setState((state) => ({

count: state.count,

}));

}

render() {

return (

{this.state.count}
click

);

}

}

这段代码也算比较直观的说明了shouldComponentUpdate的用法,为什么要这么做?当只有一个Test组件的时候可能影响不大,那如果有一千个乃至一万个Test的时候呢,每点击一次click就有一千个、一万个TestcomponentDidUpdate被调用,这就有点夸张了。所以当你在使用循环渲染组件的时候就一定要注意到这一个点,它可能会成为你应用的瓶颈。

现在我们来解一下第一个问题,每次点击click的时候,Test组件会打印Test componentDidUpdate吗?

是的,每次点击click的时候,Test组件会打印Test componentDidUpdate,除非我们在Test中定义了shouldComponentUpdate,同时返回了false阻止其重新渲染。

PureComponent


关于React的这个 API,相信大家也没有那么陌生,根据官方文档的说法ComponentPureComponent很相似,两者的区别在于PureComponent中实现了shouldComponentUpdate函数,这也是为什么我说要从shouldComponentUpdate说起。

import React from ‘react’;

class Test extends React.PureComponent {

componentDidUpdate() {

console.log(‘Test componentDidUpdate’);

}

// 错误的用法

shouldComponentUpdate(nextProps) {

if (this.props.count === nextProps.count) {

return false;

}

return true;

}

render() {

return 

;

}

}

如果你在PureComponent中又使用了shouldComponentUpdate你应该会得到这样一个警告,侧面也告诉我们PureComponent已经实现了shouldComponentUpdate这个函数了。

Test has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.

官网文档中说PureComponent中以浅层对比propsstate的方式来实现了这个函数,也就是浅比较,那什么又是浅比较呢?可以简单的理解为a === b,这里面还是有一些说头的,不过不在本文探讨范围内,举两个例子,大家可以自行搜索理解。

let a = 5;

let b = 5;

let c = {};

let d = {};

console.log(a === b); // true

console.log(c === d); // false

在来看一段因为不当的代码导致的问题,大家一定要注意这部分的内容。

import React from ‘react’;

class Test extends React.PureComponent {

// 根据从 App 中传来的 animal 渲染组件

// 在 App 中每次点击添加新的动物后, 这里还是原来的 dog

render() {

return 

Test: {this.props.animal.join(‘,’)}
;

}

}

export default class App extends React.Component {

constructor(props) {

super(props);

// 默认为一只狗

this.state = { animal: [‘dog’] };

this.handleClick = this.handleClick.bind(this);

}

// 每次点击把新的值添加进 animal 中

// 此处有一个 Bug, 由于 animal.push 方法虽然更新了原来的数组

// 但是他们还是一个数组(这个说法有些奇怪), 指针还是一样的

// 可能需要读者自行搜索理解 JS 中基本类型和引用类型的存储方式

// 所以当 Test 组件接收到新的 animal 时, 通过浅比较会发现它们其实是一样的

// 也就意味着 Test 不会重新渲染

handleClick(val) {

const { animal } = this.state;

animal.push(val)

this.setState({

animal,

});

}

// 根据 state 中的 animal 渲染组件

render() {

return (

App: {this.state.animal.join(',')}

);

}

}

看到这里相信你应该能解答第二个问题和第三个问题了,不过我们还是一起再来看看~

问:如果我把Test组件的React.Component替换为React.PureComponent,结果与上面一样吗?如果不一样,为什么?

答:因为每次传递props中的onClick都是App组件中的handleTestClick,同时使用了PureComponent,所以每次浅比较都是一致的,所以不会在打印Test componentDidUpdate了。

问:如果我修改这一行代码<Test onClick={this.handleTestClick} /><Test onClick={() => {}} />结果又如何?

答:虽然使用了PureComponent,但是由于App每次调用render函数的时候都会重新声明一个方法,此方法和上一次传递给Test的方法不同,所以每次点击还是会打印Test componentDidUpdate

剩点内容补充


除了上述两个 API 以外,其他 API 或多或少只是它们的改版,所以我就放在一起说了。

memo

React.memo在我看来就是PureComponent无状态组件版本,如果用的是class就用PureComponent,如果用的是无状态组件就用memo

import React from ‘react’;

最后

小编综合了阿里的面试题做了一份前端面试题PDF文档,里面有面试题的详细解析

虽只说了一个公司的面试,但我们可以知道大厂关注的东西并举一反三,通过一个知识点延伸到另一个知识点,这是我们要掌握的学习方法,小伙伴们在这篇有学到的请评论点赞转发告诉小编哦,谢谢大家的支持!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
10419193354991.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0tlcGxlcl9JSQ==,size_16,color_FFFFFF,t_70)

虽只说了一个公司的面试,但我们可以知道大厂关注的东西并举一反三,通过一个知识点延伸到另一个知识点,这是我们要掌握的学习方法,小伙伴们在这篇有学到的请评论点赞转发告诉小编哦,谢谢大家的支持!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-bpTOp1KW-1713455007900)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值