背景
在参与beisenCloud和pageBuilder的对接任务中,出现了这样一个问题:有两个组件同时关联了同一个属性组件,并且在constructor
和componentDidMount
内等做了一些初始化操作,当在这两个组件之间切换的时候,由于属性组件已经被首次render了,所以只进行了diff算法,并没有重新生成一个新的组件实例,从而导致了属性组件没有同步更新
方案
当然,我们可以在属性组件内添加componentWillReceiveProps
生命周期方法,通过nextProps
上的参数,将constructor
或者componentDidMount
内的初始化配置逻辑重新走一遍
然而,这涉及到一个问题:如果我们开发的很多属性组件,都有这个问题,那我们不得不在每个组件内部都实现一遍这样的逻辑,开发和维护的成本是很高的
在使用
componentWillReceiveProps
的时候,遇到一个问题需要注意下:在该方法之内,render之前调用的所有同步操作,通过this.props
访问到的props
都是旧的数据
优化
既然这逻辑是需要在多处复用的,那我们就需要将这部分逻辑抽离出来,放在高阶组件内完成,在需要的地方,通过该高阶组件装饰一下即可
该高阶组件接收一个条件方法,在
componentWillReceiveProps
生命周期方法中,将nextProps
和this.props
暴露给条件方法,通过返回值用来控制是否需要重新实例化Target
。
高阶组件内部代码实现如下
//高阶组件,解决属性组件不刷新的问题
import React, { Component } from 'react'
export default conditionalFun => Target => class Decorator extends Component{
constructor(props){
super(props)
this.state = {
'newInstance': false
}
}
componentWillReceiveProps (nextProps) {
let result = conditionalFun(nextProps, this.props)
if (result) {
this.setState({ 'newInstance': true })
} else {
this.setState({ 'newInstance': false })
}
}
render () {
let { newInstance } = this.state;
if (newInstance) {
return <Target key={Date.now()} {...this.props}/>//添加key,绕过diff,重新生成新的实例
}
return <Target {...this.props} />
}
}