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 //...
}

ipromise
584 声望25 粉丝

xxxxxx