最近项目中使用redux-form遇上性能瓶颈,
需要100行以上联动表单变得极其卡
原因
- 组件过多渲染导致! 更改一个输入框导致所有输入框都重新渲染。
解决思路
-
Field 使用 PureComponent 减少不必要的渲染[如果无效用shouldComponentUpdate ]
-
推荐使用shouldComponentUpdate 精确控制到每行及每个输入框的渲染
-
覆盖掉redux-from的onChange事件 改用onFocus和onBlur
下面代码我在FormMembers里遍历了fields,所以FormMembers重新渲染时会导致fields全部重新渲染。
优化后使用shouldComponentUpdate控制到每一行及每一个输入框的重新渲染,提高了非常多的性能!
优化前代码及结构
//表单
class Form extends Component{
render() {
return (
<div>
<form onSubmit={()=>{}}>
<table className="recipe_table" >
<FieldArray
name="members"
recipeName="herbal"
component={FormMembers}
change={change}
public_expense={public_expense}
/>
</table>
</form>
</div>)
}
}
//Members
class FormMembers extends Component{
render() {
let {fields}=this.props;
return(
<tbody>
{fields.map((item,key)=>{
console.log('//此处省略大量计算')
return (
<tr key={key} >
<td>
<Field name={`${item}.name`} component={Field}/>
</td>
</tr>
)
})}
</tbody>)
}
}
//数字输入框
class Field extends Component{
render(){
let {input}=this.props;
return <input {...input} />
}
}
复制代码
优化后
import isEqual from "lodash/isEqual";
//表单
class Form extends Component{
render() {
return (
<div>
<form onSubmit={()=>{}}>
<table className="recipe_table" >
<FieldArray
name="members"
recipeName="herbal"
component={FormMembers}
change={change}
public_expense={public_expense}
/>
</table>
</form>
</div>)
}
}
//Members
class FormMembers extends Component{
render() {
let {fields}=this.props;
return(
<tbody>
{fields.map((item,key)=>(<Line item={item} lineKey={key} />))}
</tbody>)
}
}
//每行刷新控制
class Line extends Component{
constructor(props){
super(props)
this.currData={};
}
shouldComponentUpdate(nextProps,nextState){//改用手动控制每行渲染
if(!isEqual(nextProps.fields.get(nextProps.lineKey),this.currData)){
return true;
}
return false;
}
render(){
this.currData=this.props.get(this.props.lineKey)
console.log('//此处省略大量计算')
return (
<tr key={this.props.lineKey} >
<td>
<Field name={`${item}.name`} component={Field}/>
</td>
</tr>)
}
}
//数字输入框
class Field extends Component{
shouldComponentUpdate(nextProps, nextState){//改用手动控制渲染
if(nextProps.input.name==this.props.input.name &&
nextProps.input.value==this.props.input.value &&
nextProps.className==this.props.className &&
nextProps.id==this.props.id &&
isEqual(nextProps.meta,this.props.meta)){
return false
}
return true
}
render(){
let {input}=this.props;
return <input {...input} />
}
}
复制代码