在基于简单存储的路由器中不必要的重新渲染

Unnecessary re-render in simple store based router

本文关键字:路由器 不必要 新渲染 存储 于简单 简单      更新时间:2023-09-26

我创建了一个简单的路由器,它只根据单个存储的当前状态进行路由。路由器查看它的每一个子路由,提取它的select状态,然后测试该路由是否应该根据它的when属性显示。

var Router = React.createClass({
  render: function() {
    const {children, state} = this.props;
    const activeRoute = React.Children.toArray(children).find(when);
    return React.createElement(
      activeRoute.props.component,
      Object.assign(
        {},
        activeRoute.props.select(state),
        {
          setState: this.props.setState,
        }
      )
    );
    function when(child) {
      return child.props.when(child.props.select(state));
    }
  }
});
var Route = React.createClass({
  getDefaultProps: function() {
    return {
      select: identity,
      when: alwaysTrue,
    }
  },
  render: function() {
    throw new Error('Route should never render');
  },
});

这些组件可以这样使用。

<Router state={this.state} setState={this.sState}>
    <Route component={Pets} when={this.onPets} select={this.selectPets} />
    <Route component={Home} />
</Router>

当使用why-did-you-update时,我发现它是不必要的重新渲染。我想消除这些不必要的重新渲染,但我没有这样做。导致重渲染的原因是什么?如何避免重渲染?

这里有一个工作演示。点击"查看宠物(点击这里)"可以看到控制台发出一系列可避免的重新渲染警告。

事实证明,why-did-you-update是警告我们,因为children属性之间的两个渲染是相等的,但不是相同的引用。这是因为我们在每次渲染时返回新的React.createElement

为了纠正这个问题,我可以将children移动到this.props, this.state, app上的属性,甚至全局。如果我使用es6类而不是createClass,我可以创建一个实例变量。使用这些方法之一,我可以在渲染方法中传递children

<Router state={this.state} setState={this.sState} children={routes} />