React 生命周期中有哪些坑,这些坑又如何去避免
一下这些情况就是React生命周期中常见的几个坑
getDerivedStateFromProps 容易编写反逻辑,使受控组件与非受控组件之间的区分变的模糊。该组件必须拥有一个对象格式的返回值
showldComponentUpdate主要会返回一个Boolean值,通过这个值来判断是否需要更新,主要用于性能的优化
componentWillMount 在React中已被启用,主要原因是因为在新的异步架构会导致它多次被调用,所以网络请求以及事件绑定应该放到 componentDidMount 中
componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate 与 componentDidUpdate 改造使用
在componentWillUnMount中忘记解除事件绑定、清除定时器等操作,会产生bug也会降低性能
避免这些坑
不在恰当的时候调用了不该调用的代码
在需要调用时,不要忘了调用
React中的diff算法是如何运作的
React为了优化diff算法对普通的diff算法实行了三大策略
策略一:tree diff——层级比对
由于开发过程中很少出现DOM的跨层级移动,所以tree diff忽略了DOM节点的跨层级移动。
策略二:component diff——组件对比
相同类型的两个组件,直接比较Virtual DOM树,不同类型的组件将会被判定作为脏组件处理,
直接删除或创建新的组件
策略三:element diff——节点对比
对于同一级的一组子组件,通过分配唯一的key值进行区分
调和阶段setState做了什么
代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程
经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面
在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染
在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染
Redux的实现原理
将应用状态统一放到state中由store管理state
reducer的作用是返回一个新的state去更新store中对用的state
按redux的原则,UI层每一次状态的改变都应通过action去触发,action传入对应的reducer 中,reducer返回一个新的state更新store中存放的state,这样就完成了一次状态的更新
subscribe是为store订阅监听函数,这些订阅后的监听函数是在每一次dipatch发起后依次执行、
可以添加中间件对提交的action对象进行重写
React合成事件的原理
React上注册的事件最终会绑定在document这个DOM上,而不是React组件对应的DOM,通过这种方式减少内存开销,所有的事件都绑定在document上,其他节点没有绑定事件,实际上就是事件委托的
React自身实现了一套事件冒泡机制,使用React实现的Event对象与原生Event对象不同,不能相互混用
React通过队列的形式,从触发的组件向父组件回溯,然后调用他们JSX中定义的callback
React的合成事件SyntheticEvent与浏览器的原生事件不同,也不会直接映射到原生事件
React通过对象池的形式管理合成事件对象的创建和销毁,减少了垃圾的生成和新对象内存的分配,提高了性能
React组件间的通讯
父子组件通讯
父传子:父组件通过向子组件传递 props,子组件得到 props 后进行相应的处理
子传父:利用回调函数,可以实现子组件向父组件通信:父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可以向父组件通信
Context组件通讯
使用 context 是另一种可行的方式,context 相当于一个全局变量,是一个大容器,我们可以把要通信的内容放在这个容器中,这样一来,不管嵌套有多深,都可以随意取用。
使用 context 也很简单,需要满足两个条件:
上级组件要声明自己支持 context,并提供一个函数来返回相应的 context 对象
子组件要声明自己需要使用 context
React元素的$$typeof属性
不使用$$typeof就会存在着存在着XSS攻击。如果message是用户可以控制的变量(比如说是用户输入的评论)的话,那么用户就可以进行攻击了。
比如一个网站的评论信息message是由用户提供的,并且支持传入JSON。那么如果用户直接将上文的message发送给后台保存。之后,通过 <div>{message}</div> 这种方式展示的话,用户就可以进行XSS攻击了
假设如果没有$$typeof属性的话,这种攻击确实可行。因为其他的属性都是可序列化的
但是JSON是不支持Symbol类型的。所以,即使用户提交了如上的message信息,到最后服务端也不会保存$$typeof属性。而在渲染的时候,React 会检测是否有$$typeof属性。如果没有这个属性,则拒绝处理该元素
但你的浏览器如果不支持Symbol数据类型那么这种保护方案就没有了任何效果
connect组件的原理
connect是一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的Connect组件,该组件具有如下特点:
通过props.store获取祖先Component的store
props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
componentWillUnmount时移除注册的事件this.handleChange