反应,避免使用shallowEqual重新渲染

时间:2017-04-29 12:44:08

标签: reactjs

我开始看到性能问题并尝试对其进行优化。

作为第一步,我正在处理Perf.printWasted()

这就是我试图消除不必要的渲染。

我的一个组件因为两个道具而被重新渲染

  1. new日期对象。

  2. 新创建的[todo]数组

  3. 假设您正在为待办事项创建日历 对于每个日期,我都会传递一个日期,以及当天到期的待办事项列表 我正在做(简化)

    之类的事情
    todoForDay = _.filter(todos, (todo) => {return todo.dueDate == today})
    
    反应的浅层等等不会认为这两种情况是平等的,我该怎么办?

    对于#1,我可以考虑将moment(date).format()作为道具传递,并在每次通过日期时转换回日期对象。
    但它会变得非常烦人,因为有太多的子组件需要访问日期。

3 个答案:

答案 0 :(得分:1)

您是否尝试过实施shouldComponentUpdate生命周期方法?您可以检查传入日期prop和todos数组的不等式,如下所示:

class MyComponent extends Component {
  shouldComponentUpdate(prevProps) {
    const { 
      date,
      todos,
    } = this.props;
    const {
      date: prevDate,
      todos: prevTodos,
    } = prevProps;

    return (
      date.getTime() !== prevDate.getTime() ||
      !_.isEqual(todos, prevTodos)
    );
  }

  render() {
    // render...
  }
}  

_.isEqual方法对两个todos数组进行深度相等比较。如果您想要更具体,还可以使用_.isEqualWith方法为这些数组定义自己的相等概念。

或者,您可以查看类似于Immutable.js的内容,因为它可以让您进行更轻松的todos !== prevTodos比较,但这可能对您的需求有些过分(取决于您工作的数据量)用)。

如果您已经做过类似的事情,可能会提供更多代码(您实施的shouldComponentUpdate方法,以便我们建议其他方法)。

答案 1 :(得分:0)

对于#1,你不需要转换道具。您只需将日期与getTime()中的shouldComponentUpdate()进行比较:

shouldComponentUpdate(nextProps) {
  return this.props.date.getTime() !== nextProps.date.getTime()
}

对于#2而言,不幸的是它看起来像一个包含对象的数组,我认为在这里做一个深度相等的东西比仅仅渲染更昂贵。

请注意,执行render()并不意味着DOM会获得更新。如果您正确设置key,那么它应该足够快。 (如果待办事项可能会更改其顺序,或者新添加的待办事项被添加到顶部,则不要使用索引作为密钥。在这种情况下,真正的唯一密钥更好)

您应该尽量避免不必要的setState(如果您没有使用状态管理库)。还尝试将组件拆分为小块。而不是每次更新时重新渲染一个巨大的组件,只更新应用程序的最小部分应该更快。

另一种可能性是重建你的国家。但它基于您的要求。如果您不需要每个待办事项的完整日期时间,您可以将您的状态分组为:

todos: {
  '2017-04-28': ['Watch movie', 'Jogging'],
  '2017-04-29': ['Buy milk']
}

通过这样做,您甚至不需要过滤器。你可以轻松地抓住你想要的日期。

在更复杂的情况下,您需要更多信息,您可以尝试规范化您的州,例如:

{
  todos: {
    1: { text: 'Watch movie', completed: true, addedTime: 1493476371925 },
    2: { text: 'Jogging', completed: true, addedTime: xxxxxxxxxx},
    3: { text: 'Buy milk', completed: false, addedTime: xxxxxxxxxx}
  },
  byDate: {
    '2017-04-28': [1, 2],
    '2017-04-29': [3]
  }
}

现在,如果向todos添加新的待办事项,则不会影响您引用byDate的组件,因此您可以确保没有不必要的重新渲染。< / p>

答案 2 :(得分:0)

我正在分享我的解决方案。

对于基于日历的待办事项列表,我希望避免在一个日历日为每个子组件实施shouldComponentUpdate

所以我找了一种方法来缓存我为日历创建的日期。 (除非您更改月份,否则您会看到相同的日期范围)。

所以https://github.com/reactjs/reselect非常适合。

我也用重新选择解决了#2。

它记忆(缓存)函数结果直到函数params改变。