1.memo

其实react.memo的实现很简单,就几行代码。

export default function memo<Props>(type: React$ElementType,compare?: (oldProps: Props, newProps: Props) => boolean,
) {if (__DEV__) {if (!isValidElementType(type)) {warningWithoutStack(false,'memo: The first argument must be a component. Instead ' +'received: %s',type === null ? 'null' : typeof type,);}}return {$$typeof: REACT_MEMO_TYPE,type,compare: compare === undefined ? null : compare,};
}
复制代码

可以看到,最终返回的是一个对象,这个对象带有一些标志属性,在react Fiber的过程中会做相应的处理。

在ReactFiberBeginWork.js中可以看到:

if (updateExpirationTime < renderExpirationTime) {// This will be the props with resolved defaultProps,// unlike current.memoizedProps which will be the unresolved ones.const prevProps = currentChild.memoizedProps;// Default to shallow comparisonlet compare = Component.compare;compare = compare !== null ? compare : shallowEqual;if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {return bailoutOnAlreadyFinishedWork(current,workInProgress,renderExpirationTime,);}}
复制代码

根据传入的compare函数比较prevPropsnextProps,最终决定生成对象,并影响渲染效果。

其实在这之前,早已经有一个生命周期函数实现了相同的功能。他就是shouldComponentUpdate

之所以再增加这个memo,也是react团队一直在秉承的信念。那就是让一切变得更加函数式

通过一个例子来看看memo如何使用。

先创建一个简单组件SubComponent

const SubComponent = props => <>i am {props.name}. hi~</>
复制代码

调用React.memo创建memo组件

const Memo = React.memo(SubComponent, (prevProps, nextProps) => prevProps.name === nextProps.name
);
复制代码

在页面上调用memo

<div className="App"><Memo name={name} />
</div>
复制代码

memo接收两个参数,一个是组件,一个是函数。这个函数就是定义了memo需不需要render的钩子。

比较前一次的props跟当前props,返回true表示不需要render。

也就是传给Memo的name不变时,不会触发SubComponent的render函数。

当前页面上的SubComponent还是之前的,并没有重新渲染。这也是为啥叫memo的原因吧。

2.lazy and suspence

React.lazy 用于做Code-Splitting,代码拆分。类似于按需加载,渲染的时候才加载代码。

用法如下:

import React, {lazy} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));function MyComponent() {return (<div><OtherComponent /></div>);
}
复制代码

lazy(() => import('./OtherComponent'))使用es6的import()返回一个promise,类似于:

lazy(() => new Promise(resolve =>setTimeout(() =>resolve(// 模拟ES Module{// 模拟export default default: function render() {return <div>Other Component</div>}}),3000)
));
复制代码

React.lazy的提出是一种更优雅的条件渲染解决方案。

之所以说他更优雅,是因为他将条件渲染的优化提升到了框架层。

这里我们引出suspense。

当我们组件未渲染完成,需要loading时,可以这么写:

const OtherComponent = React.lazy(() => import('./OtherComponent'));function MyComponent() {return (<div><Suspense fallback={<div>Loading...</div>}><OtherComponent /></Suspense></div>);
}
复制代码

在我们的业务场景中,OtherComponent可以代表多个条件渲染组件,我们全部加载完成才取消loding。

只要promise没执行到resolve,suspense都会返回fallback中的loading。

代码简洁,loading可提升至祖先组件,易聚合。相当优雅的解决了条件渲染。

关于suspense的异步渲染原理有篇文章写的很好,感兴趣的在文末查看。

3.hooks(重点介绍useEffect)

hooks提出有一段时间了,dan也一直在推广,并且表示很快加入react正式版本。

关于一些介绍,直接看官网会更好。

hooks常用api有:useState、useEffect、useContext、useReducer、useRef等。

主要操作一下useEffect,用处很大。举一反三。

all is function,没了component,自然也没了各种生命周期函数,此时useEffect登场。

下面通过一个组件实例来说明。

影像组件,功能有:前端加水印、实现拖拽。

大致实现如下:

class ImageModal extends Component {constructor(props) {...}componentDidMount() {// 画水印、注册拖拽事件逻辑// 以及其他的image处理相关逻辑}componentDidUpdate(nextProps, prevProps) {if (nextProps.cur !== prevProps.cur) {// 切换时重置状态(比如 旋转角度、大小等)逻辑// image特有逻辑}}render() {return <>...<img ... /></img>}
}
复制代码

ImageModal负责渲染图片modal,现在有另一个modal用来渲染html模板。

命名为HtmlModal,HtmlModal接受后端返回的html,经过处理后内嵌在网页中。

同样要求加水印、拖拽的功能等。

也就是image跟html有部分逻辑相同有部分不相同。

基于这个考虑,再写一个组件。

同理实现如下:

class HtmlModal extends Component {constructor(props) {...}componentDidMount() {// 画水印、注册拖拽事件逻辑// 以及其他的html处理相关逻辑}componentDidUpdate(nextProps, prevProps) {if (nextProps.cur !== prevProps.cur) {// 切换时重置状态(比如 旋转角度、大小等)逻辑// html特有逻辑}}render() {return <>...<div dangerouslySetInnerHTML={{ __html: ... }}></div></img>}
}
复制代码

可以看到HtmlModalImageModalcomponentDidMountcomponentDidUpdate周期中有不少逻辑是相同的。

如果我们使用useEffect的话,可以怎么实现这个复用和分离呢?来看看。

export function useMoveEffect() {// 第二个参数传了固定值 [] // 相当于 componentDidMountuseEffect(() => {// 实现拖拽逻辑}, []);
}export function useDrawMarkEffect(cur) {useEffect(() => {// 实现水印逻辑}, []);
}export function useResetEffect(cur); {// 第二个参数传了固定值 [ cur ] // 相当于 componentDidUpdate 比较 curuseEffect(() => {// 实现重置逻辑}, [ cur ]);
}function useOtherImageEffect(...) {useEffect(() => {// 实现image特有逻辑}, [ ... ]);
}function ImageModal (props) {// 细分 Effect,方便复用useMoveEffect();useDrawMarkEffect();useResetEffect(props.cur);...useOtherImageEffect(...);return <>...<img ... /></img>}
复制代码

ok,有了上面的梳理和useEffect重构,我们来编写HtmlModal:

import { useMoveEffect, useDrawMarkEffect, useResetEffect } from './imageModal'function useOtherHtmlEffect(...) {useEffect(() => {// 实现html特有逻辑}, [ ... ]);
}function HtmlModal (props) {// 细分 Effect,方便复用useMoveEffect();useDrawMarkEffect();useResetEffect(props.cur);...useOtherHtmlEffect(...);return <>...<img ... /></img>}
复制代码

以上,实现了生命周期中重复逻辑的复用。以后无论新增什么modal,都可以复用逻辑,摆脱了 ctr c/ ctr v

从而组件变得更小、代码变得简洁,提升编程体验。

参考资料: React v16.6.0: lazy, memo and contextType(官网)

Hooks API Reference(官网)

Making Sense of React Hooks(dan)

React Suspense(中文)

觉得有帮助的点个赞,甚至可以关注一波哦~

react新特性实例详解(memo、lazy、suspense、hooks)相关推荐

  1. JDK13的新特性:AppCDS详解

    文章目录 简介 基本步骤 JDK class文件归档 创建JDK class-data archive 使用JDK class-data archive启动应用程序 运行时间对比 应用程序class文 ...

  2. Go1.20 arena新特性示例详解

    当时我们还想着 Go 团队应该不会接纳,至少不会那么快: 懒得翻也可以看我再次道来,本文提到的提案<proposal: arena: new package providing memory a ...

  3. Oracle 11g R2 Clusterware新特性 – HAIP详解

    By luocs ( 十二月 18, 2012 at 上午 8:23) 前段时间在聊RAC私网(Private Network)冗余技术的时候,朋友们大多搬出Bonding技术,当时我说了个HAIP, ...

  4. Visual Studio 11 九大新特性:图文详解【转】

    转自: [IT168 技术]导读:之前Visual Studio 11开发者预览版发布的消息受到了众多技术人员的关注和讨论.日前Visual Studio 11最新的Beta版本在巴塞罗那正式推出.我 ...

  5. Crytek CryEngine 3新特性完全详解

    转自 http://news.mydrivers.com/1/131/131028.htm 作为声名显赫的CryENGINE引擎的第三代,CryENGINE 3继承了前辈在画质方面的突出造诣,而且这次 ...

  6. CryENGINE 3游戏引擎新特性完全详解

     作为声名显赫的CryENGINE引擎的第三代,CryENGINE 3继承了前辈在画质方面的突出造诣,而且这次不仅限于PC平台,还可用于PS3和X360等主机平台,这也是Crytek首次进军游戏机 ...

  7. 百度地图(HTML5新特性)-全面详解(学习总结---从入门到深化)

    目录 百度地图_账号和获取密钥 百度地图_初始化 百度地图_变更地图类型 百度地图_添加控件 百度地图_改变控件位置 百度地图_添加覆盖物 百度地图_自定义标注图标 百度地图_添加文本标注 百度地图_ ...

  8. java切片_ java中一个极其强悍的新特性Stream详解(非常实用)

    java8中有两个非常有名的改进,一个是Lambda表达式,一个是Stream.如果我们了解过函数式编程的话,都知道Stream真正把函数式编程的风格引入到了java中.这篇文章由简入繁逐步介绍Str ...

  9. 【PCIe 6.0】PCIe 6.0 新特性 - L0p 详解

最新文章

  1. 解决Mac Pro上IDEA卡顿的问题
  2. python全排序算法题_Python的100道经典算法题(1)
  3. 开心一刻,你和导师之间有什么有趣的事情?
  4. JMM设计原理之双重检查Lock
  5. Redis数据安全与性能保障——redis读书笔记4
  6. C#基础---Queue(队列)的应用
  7. openstack手动部署简单记录
  8. mysql web报表_2021最新流行的Web报表工具推荐
  9. c语言getch函数_在C / C ++中使用getch()函数
  10. 电工学习笔记————稳压二极管伏安特性
  11. 已有的MGR集群上配置InnoDB Cluster
  12. 关于XAMPP Apache 启动失败的问题
  13. allegro16.6使用汇总
  14. Intel汇编-部分余数
  15. 论文参考文献格式标准
  16. Matlab2020a安装
  17. 9017R单节锂电池线性充电管理 IC
  18. 如何用python完成评分功能呢_Python:豆瓣电影评分
  19. 微信小程序+云函数+腾讯云对话机器人API(ChatBot)
  20. 华强北发挥作用的时候到了!iPhone12更换零件需要官方授权

热门文章

  1. jq ajax xml,jQuery+ajax读取并解析XML文件的方法
  2. java jsm_JSM 基础
  3. tracepro杂散光分析例子_2020临中高考咨询群咨询成效问卷结果分析
  4. python可以用eclipse开发吗_Eclipse不是主要用来写Java么?Python也可以在eclipse上面写?Eclipse搭建Python开发环境...
  5. oracle怎么装系统,【Oracle安装与操作系统用户组】
  6. java+c#+json+时间_Java与C#间json日期格式互转完美解决方案
  7. python中prime_在AP中查找第一个元素,该元素是Python中给定Prime的倍数
  8. 没有varselect这个函数_JavaScript学习笔记(四)-- 函数基础
  9. 为什么要使用 dns-prefetch
  10. Web前端精髓年终总结