redux-form效能優化

weixin_34166847發表於2018-01-02

最近專案中使用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} />
	}
}
複製程式碼

建議使用 reselect 優化效能

github.com/reactjs/res…

相關文章