React 性能优化初探

发布于 2021-08-29 11:21:46 字数 3708 浏览 1094 评论 0

不要将当前 container 没有用到的 state 绑定到 props

// src/example1/containers/CounterContainer.js
export default connect(state => ({
  total: state.example1.total,
}), { increment })(CounterContainer);

// src/example1/containers/RandomNumContainer.js
export default connect(state => ({
  randomNum: state.example1.randomNum,
}), { setRandomNum })(RandomNumContainer);

当组件 CounterContainer 中 total 改变时,不会引起 RandomNumContainer 组件 render

如果在 RandomNumCountainer 中加入没有用到的 total 变量时

// src/example1/containers/RandomNumContainer.js
export default connect(state => ({
  randomNum: state.example1.randomNum,
  total: state.example1.total,
}), { setRandomNum })(RandomNumContainer);

组件 CounterContainer 中 total 改变时,会引起 RandomNumContainer 组件 render

需要多次使用 state 计算得到的数据,请使用 reselect 缓存

// src/example2/containers/CounterContainer.js
// 主要函数
...
  get formatTotal() {
    const { total } = this.props;

    console.log('call formatTotal()');
    // 复杂的计算
    return total * 10;
  }

  render() {
    const { total, clickTime } = this.props;

    return (
      <div>
        <span>CounterContainer: { total }</span>
        <button onClick={this.handleClick}>+</button>

        <div>格式化后的total: { this.formatTotal }</div>
        <div>格式化后的total2: { this.formatTotal }</div>

        <button onClick={this.handleTimeClick}>获取点击时间: { clickTime }</button>
      </div>
    );
  }
...

1. 点击+号后,会调用两次formatTotal
call formatTotal()
call formatTotal()
2. 点击获取点击时间,会调用两次formatTotal
call formatTotal()
call formatTotal()

如果,formatTotal是一个复杂计算的函数,性能是堪忧的。

使用selector优化后的版本

// 将formatTotal传递到组件的props中

const getTotal = state => state.example2.total;
const formatTotal = createSelector(
  [getTotal],
  (total) => {
    console.log('call formatTotal()');

    return total + 10;
  },
);

export default connect(state => ({
  total: state.example2.total,
  clickTime: state.example2.clickTime,
  formatTotal: formatTotal(state),
}), { increment, setClickTime })(CounterOptimizeContainer);

注意:

  1. 不要将当前 container 没有用到的 state 绑定到 props
  2. 需要多次使用 state 计算得到的数据,请使用 reselect 缓存
  3. 使用 PureComponent 替代 Component,避免不必要的render
  4. 尽量将大组件进行拆分,避免兄弟组件的state改变,引起自身重复render
  5. 避免不必要的 props 更新。
    1. 避免在render函数中使用 this.handleClick.bind(this) 以及 (id) => this.handleClick(id),如需绑定 this,请在constructor中绑定this.handleClick = this.handleClick.bind(this), 如需绑定特定属性值,可以将该组件封装成子组件<ChildComponent data={item} onClick={this.handleClick} />,在子组件中处理回调。
    2. <Component list={data || []} />
    3. 请慎用 {…this.props},尽量只传递子组件需要的props
  6. 子组件使用 shouldComponentUpdate 时,如果父组件直接修改state值,会因为引用赋值的缘故,继而导致子组件中props值一起改变,这时,即使父组件调用setState更新了子组件的props, 子组件中shouldComponentUpdate也会判断失败,导致子组件更新失败。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文