React 技术总结

1,005 阅读10分钟

React 组件通讯方式

react 组件间通信常见的几种情况

  • 父组件向子组件通信
  • 子组件向父组件通信
  • 跨级组件通信
  • 非嵌套关系的组件通信

1) 父组件向子组件通信:父组件通过props向子组件传递需要的信息

2) 子组件向父组件通信:props + 回调的方式

3) 跨级组件通信: 即父组件向子孙组件通信,通过context 实现

4) 非嵌套关系的组件通信:即没有任何包含关系的组件,包括兄弟组件不在同一层级的组件

1.可以使用自定义时间通信(发布订阅模式)
2.可以通过redux等进行全局状态管理
3.如果是兄弟节点通信,可以找到两个兄弟节点共同的父节点,结合父节点通信的方式

React事件绑定原理

React 并不是将click事件绑定在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行,这样的方式不仅减少了内存消耗,还能在组件挂载销毁时统一订阅和移除事件。

另外冒泡都document上的事件 也不是原生的事件,而是React自己实现的合成事件(syntheticEvent)

为什么要使用合成事件机制

  1. 更好的兼容性和跨平台

  2. 挂载到document 减少内存消耗 避免重复解绑

  3. 方便事件统一管理

React Fibler

背景

React在进行组件渲染时,从setState开始到渲染完成整个过程时同步的,如果需要渲染的组件比较多,js执行会占据主线程的时间就会很长,会导致页面响应变慢,使react在动画,手势等应用中效果比较差。

React项目中那些细节可以优化?实际开发中都做过什么性能优化

1)对于正常的项目优化,一般都涉及到几个方面,开发过程中,上线之后的首屏,运行过程的状态

  • 上线之后的首屏及运行状态:

    1. 首屏优化一般涉及几个指标FP,FCP,FMP,要有一个良好的体验是尽可能的把FCP提前,需要做一些工程化的处理,优化资源的加载,FP(页面在导航后首次呈现出不同于导航前内容的时间点),FCP( 首次绘制任何文本,图像,非空白canvas或SVG的时间点)FMP(First Meaningful Paint): 首次绘制页面“主要内容”的时间点。

    2. 方式及分包策略,资源的减少是最有效的加快首屏打开的方式

    3. 对于客户端渲染(CSR)的应用,FCP的过程一般是首先加载js,css的资源,js在本地执行完成,然后加载数据,初始化渲染,中间就会有几次网络请求的过程;所以客户端渲染可以考虑使用骨架屏及预渲染,suspence与lazy做懒加载动态组件的方式

    4. 还有一种方式就是SSR的方式,SSR对于首屏的优化有一定的优势

    5. 不管是CSR还是SSR,建议配合使用Service worker 控制资源的调配骨架屏秒开的体验

    6. react上线之后,首先需要保障的是可用性,所以通过React.Profiler分析组件的渲染次数和耗时的一些任务,但是Profile记录的是commit阶段的数据,所以对于React的调和阶段就需要performance API一起分析

    7. 由于React是父级props改变之后,所有与props不相关子组件在没有添加条件控制的情况之下,也会触发render渲染,这是没有必要的,可以结合React的PureComponent以及React.memo做浅比较,这中间有涉及到不可变值数据处理,当然也可以使用React生命周期 shouldComponentUpdate做深比较处理。

    8. 所有的运行状态都是减少不必要的render,React.useMemo和React.useCallback也可以做一些优化

    9. 可以使用React生命周期componentDidCatch 做一些错误边界处理

    总结React实际开发中需要优化的点,如下:

    1. 首屏优化中尽量将FCP提前,需要做一些工程化处理,优化资源加载
    2. 使用骨架屏及预渲染的方式
    3. 使用suspence和lazy的方式动态加载组件
    4. 使用服务端渲染(SSR),加快首屏打开速度
    5. 使用React的PureComponent,Reacxt.memo,shouldComponentUpdate
    6. 使用React hooks中 useMemo,useCallback
    7. 保证数据的不可变性(React不可变值)
    8. React 列表渲染的时候使用唯一key
    9. 使用自定义事件,DOM事件,在React生命周期componentWillunMount中销毁
    10. 在React中DOM元素中 减少函数bind this的方式,尽量使用箭头函数或者constructor中bind的方式
    11. 使用Immutable.js 不可变库,但是开发成本会提高
    12. 不在render中处理数据
    13. 减少不必要的标签,使用React.Fragments或者<>内容</> 这种标签的方式

React props和state的区别

区别:

  1. props 是传递给组件的,而state是组件内被组件自己管理的
  2. props 是不可修改的
  3. state 是组件中创建的,一般在构造函数中初始化
  4. state 是可以修改的,每次setState 都异步更新state

那些方法会触发react 重新渲染?重新渲染render会做些什么?

  1. 那些方法会触发react重新渲染?

    1) setState() 被调用的时候

    通常情况下触发setState会触发render,但是有个别情况就是setState传入null的时候,并不会触发render

    2)父组件重新渲染

  2. 重新渲染 render 会做些什么?

    1)会对新旧Vnode进行对比,dom diff 2)对新旧两棵树进行一个深度的遍历,这样每一个节点都会被标记,在到深度比你的时候,每遍历到一个节点,就吧该节点和新的节点进行对比,把差异放到一个对象中 3)遍历差异对象,根据差异的类型,规则更新VNode

React 中setState 后发生了什么?setState为什么默认是异步?setState什么时候同步?

  1. React 中setState 后发生了什么

    在代码中调用setState函数之后,React会将传入的参数newState加入到组件内部的pendding队列中,判断是否处理batchUpdate 模式,如果是将加入到dirtyComponents中,如果不是遍历dirtyComponents 然后执行updateComponent props or state

  2. setState为什么默认是异步

    因为React 如果setState默认是同步的,用户每一次执行setState进行dom操作,当有多个setState同时进行时,频繁操作dom比较耗性能,如果是异步,可以把一个多个setState合并成一个组件更新。

  3. setState什么时候同步?

setState只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。 setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”

React 组件中怎么做事件代理?它的原理是什么?

React基于vdom实现了一个SyntheticEvent(合成事件),定义的事件处理器会接收到一个合成事件的实例,且与原生的浏览器事件拥有同样的接口,支持冒泡机制。

在React底层主要对合成事件做了:事件委派和自动绑定

事件委派:React会把所有的事件绑定到结构的最外层(document上),使用统一的事件监听器 自动绑定:React组件中,每个方法的上下文都会指向该数组的实例,即自动绑定this为当前组件

React 非受控组件

非受控组件就是组件的值不受React state 控制,非受控组件 使用defaultValue设置默认值,必须手动操作DOM元素,setState实现不了

使用场景:1. 文件上传 2. 富文本等

React setState的过程

  1. 每个组件实例子,都有renderComponent方法
  2. 执行renderComponent,会重新执行React render方法
  3. render 方法返回一个newVnode,找到之前的preVnode
  4. 执行patch(preVnode,newVnode)【其中执行dom diff 找出差异】渲染出真实的dom

React与Angular有何不同

  1. React是MVC中的View层,Angular是完整的MVC结构
  2. React既可以实现客户端渲染也可以服务端渲染,Angular是客户端渲染
  3. React 是单项数据流,Angular是双向绑定
  4. React 是虚拟dom,Angular是真实的dom

react 生命周期

React生命周期分为3个阶段

  1. 挂载阶段

    constructor -> getDerivedStateFromProps -> render -> componentDidMount

  2. 更新阶段

    getDerivedStateFromProps->shouldComponentUpdate-> render -> getSnapshotBeforeUpdate -> componentDidUpdate-> render

  3. 卸载阶段

    componentWillUnMount

React 有状态组件和无状态组件区别,以及为什么要使用,它的优缺点

一. 有状态组件 特点:

  • 是一个类组件
  • 有继承
  • 可以使用this
  • 可以使用react 生命周期
  • 使用较多,容易频繁发生生命周期钩子函数,影响性能
  • 内部使用state,维护自身状态的变化,有状态组件根据外部组件传入的props 和自身的state,进行渲染。

使用场景:

  • 需要使用状态的
  • 需要使用状态操作组件的

总结: 类组件可以维护自身的状态state,类组件还有不同的生命周期方法,可以让开发者能够在组件的不同杰顿啊,对组件做控制

二.无状态组件 特点:

  • 不依赖自身的状态
  • 可以是类组件或者函数组件
  • 可以完全避免使用this
  • 组件中不使用生命周期或者状态state是优先使用无状态组件
  • 组件内部不维护state,只根据外部的props进行渲染组件,当props改变时,组件重新渲染 使用场景: 组件不需要state,单纯的渲染

总结: 组件内部状态且与外部无关的组件,可以考虑状态组件 当一个组件不需要管理自身状态时,也就是无状态组件,应该考虑无状态组件

三. 无状态组件的优缺点

优点:

  • 组件不需要被实例,无自身的state,无钩子生命周期
  • 组件渲染只取决于props

缺点:

  • 无法使用ref
  • 无生命周期
  • 无法控制组件的重渲染,因为无法使用shouldComponentUpdate方法

React 高阶组件 , render props , hooks 有什么区别

高阶组件: 高阶组件(HOC) 是一种组件的设计模式,HOC接受一个组件为入参,返回一个新的组件,HOC是一个纯函数没有副作用 优点:逻辑复用,不影响组件的内部逻辑 缺点:hoc传递给组件的props容易和包裹后的组件重名,进而被覆盖

render props render props 是指一种在React组件之间用一个值为函数的props共享代码的技术 优势:

  • 数据共享,代码复用,将组件内的state作为props传递给调用者,将渲染逻辑交给调用者 缺点:
  • 无法在return外访问数据,嵌套写法不够好

Hooks Hooks是react16.8推出的,可以让不编写类组件的情况下,在函数式组件哪使用state以及其他特性,通过自定义hooks可以代码复用

优点:

  • 解决hoc和prop重名问题
  • 解决render props 共享数据 出现嵌套多的问题
  • 能在retuen外使用数据的问题

React组件的构造函数有什么作用?

  1. 指定super(props)
  2. 初始化state
  3. 为组件上的构造函数绑定this

super() 和 super(props)有什么区别

react 中的class是基于es6实现,继承是使用extends 实现继承,子类必须在constructor()中调用super()方法否则新建实例

  1. 如果你使用了constructor就必须写super() 这个是用来初始化this的,可以绑定事件到this上2. 如果你想要在constructor中使用this.props,就必须给super添加参数 super(props)