Component或PureComponent

53次阅读

共计 1663 个字符,预计需要花费 5 分钟才能阅读完成。

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

正文完
 0