React 组件通讯方式
react 组件间通信常见的几种情况
- 父组件向子组件通信
- 子组件向父组件通信
- 跨级组件通信
- 非嵌套关系的组件通信
1) 父组件向子组件通信:父组件通过props向子组件传递需要的信息
2) 子组件向父组件通信:props + 回调的方式
3) 跨级组件通信: 即父组件向子孙组件通信,通过context 实现
4) 非嵌套关系的组件通信:即没有任何包含关系的组件,包括兄弟组件不在同一层级的组件
1.可以使用自定义时间通信(发布订阅模式)
2.可以通过redux等进行全局状态管理
3.如果是兄弟节点通信,可以找到两个兄弟节点共同的父节点,结合父节点通信的方式
React事件绑定原理
React 并不是将click事件绑定在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行,这样的方式不仅减少了内存消耗,还能在组件挂载销毁时统一订阅和移除事件。
另外冒泡都document上的事件 也不是原生的事件,而是React自己实现的合成事件(syntheticEvent)
为什么要使用合成事件机制
-
更好的兼容性和跨平台
-
挂载到document 减少内存消耗 避免重复解绑
-
方便事件统一管理
React Fibler
背景
React在进行组件渲染时,从setState开始到渲染完成整个过程时同步的,如果需要渲染的组件比较多,js执行会占据主线程的时间就会很长,会导致页面响应变慢,使react在动画,手势等应用中效果比较差。
React项目中那些细节可以优化?实际开发中都做过什么性能优化
1)对于正常的项目优化,一般都涉及到几个方面,开发过程中,上线之后的首屏,运行过程的状态
-
上线之后的首屏及运行状态:
-
首屏优化一般涉及几个指标FP,FCP,FMP,要有一个良好的体验是尽可能的把FCP提前,需要做一些工程化的处理,优化资源的加载,FP(页面在导航后首次呈现出不同于导航前内容的时间点),FCP( 首次绘制任何文本,图像,非空白canvas或SVG的时间点)FMP(First Meaningful Paint): 首次绘制页面“主要内容”的时间点。
-
方式及分包策略,资源的减少是最有效的加快首屏打开的方式
-
对于客户端渲染(CSR)的应用,FCP的过程一般是首先加载js,css的资源,js在本地执行完成,然后加载数据,初始化渲染,中间就会有几次网络请求的过程;所以客户端渲染可以考虑使用骨架屏及预渲染,suspence与lazy做懒加载动态组件的方式
-
还有一种方式就是SSR的方式,SSR对于首屏的优化有一定的优势
-
不管是CSR还是SSR,建议配合使用Service worker 控制资源的调配骨架屏秒开的体验
-
react上线之后,首先需要保障的是可用性,所以通过React.Profiler分析组件的渲染次数和耗时的一些任务,但是Profile记录的是commit阶段的数据,所以对于React的调和阶段就需要performance API一起分析
-
由于React是父级props改变之后,所有与props不相关子组件在没有添加条件控制的情况之下,也会触发render渲染,这是没有必要的,可以结合React的PureComponent以及React.memo做浅比较,这中间有涉及到不可变值数据处理,当然也可以使用React生命周期 shouldComponentUpdate做深比较处理。
-
所有的运行状态都是减少不必要的render,React.useMemo和React.useCallback也可以做一些优化
-
可以使用React生命周期componentDidCatch 做一些错误边界处理
总结React实际开发中需要优化的点,如下:
- 首屏优化中尽量将FCP提前,需要做一些工程化处理,优化资源加载
- 使用骨架屏及预渲染的方式
- 使用suspence和lazy的方式动态加载组件
- 使用服务端渲染(SSR),加快首屏打开速度
- 使用React的PureComponent,Reacxt.memo,shouldComponentUpdate
- 使用React hooks中 useMemo,useCallback
- 保证数据的不可变性(React不可变值)
- React 列表渲染的时候使用唯一key
- 使用自定义事件,DOM事件,在React生命周期componentWillunMount中销毁
- 在React中DOM元素中 减少函数bind this的方式,尽量使用箭头函数或者constructor中bind的方式
- 使用Immutable.js 不可变库,但是开发成本会提高
- 不在render中处理数据
- 减少不必要的标签,使用React.Fragments或者<>内容</> 这种标签的方式
-
React props和state的区别
区别:
- props 是传递给组件的,而state是组件内被组件自己管理的
- props 是不可修改的
- state 是组件中创建的,一般在构造函数中初始化
- state 是可以修改的,每次setState 都异步更新state
那些方法会触发react 重新渲染?重新渲染render会做些什么?
-
那些方法会触发react重新渲染?
1) setState() 被调用的时候
通常情况下触发setState会触发render,但是有个别情况就是setState传入null的时候,并不会触发render
2)父组件重新渲染
-
重新渲染 render 会做些什么?
1)会对新旧Vnode进行对比,dom diff 2)对新旧两棵树进行一个深度的遍历,这样每一个节点都会被标记,在到深度比你的时候,每遍历到一个节点,就吧该节点和新的节点进行对比,把差异放到一个对象中 3)遍历差异对象,根据差异的类型,规则更新VNode
React 中setState 后发生了什么?setState为什么默认是异步?setState什么时候同步?
-
React 中setState 后发生了什么
在代码中调用setState函数之后,React会将传入的参数newState加入到组件内部的pendding队列中,判断是否处理batchUpdate 模式,如果是将加入到dirtyComponents中,如果不是遍历dirtyComponents 然后执行updateComponent props or state
-
setState为什么默认是异步
因为React 如果setState默认是同步的,用户每一次执行setState进行dom操作,当有多个setState同时进行时,频繁操作dom比较耗性能,如果是异步,可以把一个多个setState合并成一个组件更新。
-
setState什么时候同步?
setState只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。 setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”
React 组件中怎么做事件代理?它的原理是什么?
React基于vdom实现了一个SyntheticEvent(合成事件),定义的事件处理器会接收到一个合成事件的实例,且与原生的浏览器事件拥有同样的接口,支持冒泡机制。
在React底层主要对合成事件做了:事件委派和自动绑定
事件委派:React会把所有的事件绑定到结构的最外层(document上),使用统一的事件监听器 自动绑定:React组件中,每个方法的上下文都会指向该数组的实例,即自动绑定this为当前组件
React 非受控组件
非受控组件就是组件的值不受React state 控制,非受控组件 使用defaultValue设置默认值,必须手动操作DOM元素,setState实现不了
使用场景:1. 文件上传 2. 富文本等
React setState的过程
- 每个组件实例子,都有renderComponent方法
- 执行renderComponent,会重新执行React render方法
- render 方法返回一个newVnode,找到之前的preVnode
- 执行patch(preVnode,newVnode)【其中执行dom diff 找出差异】渲染出真实的dom
React与Angular有何不同
- React是MVC中的View层,Angular是完整的MVC结构
- React既可以实现客户端渲染也可以服务端渲染,Angular是客户端渲染
- React 是单项数据流,Angular是双向绑定
- React 是虚拟dom,Angular是真实的dom
react 生命周期
React生命周期分为3个阶段
-
挂载阶段
constructor -> getDerivedStateFromProps -> render -> componentDidMount
-
更新阶段
getDerivedStateFromProps->shouldComponentUpdate-> render -> getSnapshotBeforeUpdate -> componentDidUpdate-> render
-
卸载阶段
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组件的构造函数有什么作用?
- 指定super(props)
- 初始化state
- 为组件上的构造函数绑定this
super() 和 super(props)有什么区别
react 中的class是基于es6实现,继承是使用extends 实现继承,子类必须在constructor()中调用super()方法否则新建实例
- 如果你使用了constructor就必须写super() 这个是用来初始化this的,可以绑定事件到this上2. 如果你想要在constructor中使用this.props,就必须给super添加参数 super(props)