Component或PureComponent
PureComponent,前身是 PureRenderMixin ,和 Component 基本一样,只不过会在 render 之前帮组件自动执行一次shallowEqual(浅比较),来决定是否更新组件,浅比较类似于浅复制,只会比较第一层
Component只要setState()和props的改变就会触发render
而我们不想页面重新render就得自己写shouldComponentUpdate来拦截render
shouldComponentUpdate(nextProps, nextState) {
return nextProps.xxx.xx === props.xxx.xx;
}
PureComponent
PureComponent为你处理shouldComponentUpdate事件。
当props或state发生变化,PureComponent会对两者都做浅比较;
而Component则不会对两者的新旧值进行比较。
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps)
|| !shallowEqual(inst.state, nextState);
}
浅比较
浅比较只会检查基本数据类型的值是否相等(比如:1等于1或者true等于true),复杂如对象和数组只是比较引用值
并且只会去比较第一层的,不会递归去比较,那样render会更复杂
注意问题
易变数据不能使用一个引用
会发现,无论怎么点 delete 按钮, li 都不会变少,因为 items 用的是一个引用, shallowEqual 的结果为 true 。
这里的items其实都是指向state中的items来操作的,本质上引用并没有改变,不会触发render
class App extends PureComponent {
state = {
items: [1, 2, 3]
}
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items });
}
render() {
return (<div>
<ul>
{this.state.items.map(i => <li key={i}>{i}</li>)}
</ul>
<button onClick={this.handleClick}>delete</button>
</div>)
}
}
想要触发render得让引用改变
handleClick = () => {
const { items } = this.state;
items.pop();
this.setState({ items: [].concat(items) });
}
父组件向子组件传递函数
父组件里面有一组子组件列表,每一个都传给父组件方法一个唯一的参数。为了绑定这个参数,你可能这样做:
<CommentItem likeComment={() => this.likeComment(user.id)} />
问题是每一次父组件的render方法调用时,() => this.likeComment(user.id)都会执行返回一个新函数(伴随着新的引用)就会被创建并且传递给likeComment属性。
这样子组件的props的浅比较时就会发现props引用变了导致render
所以我们要这样写可以减少render
<CommentItem likeComment={this.likeComment} userID={user.id} />
在render方法中获取数据需要特别注意
下面这段代码中父组件每次render topTen的引用都会重新生成(变了)就会导致子组件用了这个变量的render
render() {
const { posts } = this.props
const topTen = posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
return //...
}