【问题标题】:skip re-render using shouldComponentUpdate and nextState使用 shouldComponentUpdate 和 nextState 跳过重新渲染
【发布时间】:2021-11-30 22:51:56
【问题描述】:

我目前有一个下拉列表select 在“应用”之后过滤一些图表。它工作正常。(见下面的截图)。

The problem is that when another timespan gets selected, React does a re-render to all charts before I click 'Apply' button.

我想通过实现shouldComponentUpdate 来避免这种不必要的重新渲染,但我不知道怎么做。

低于我尝试但它不起作用(仍然是重新渲染):

shouldComponentUpdate(nextState) {
        if (this.state.timespanState !== nextState.timespanState) {
            return true;
        }
        
        return false;
    }

但它总是返回true,因为nextState.timespanStateundefined。为什么?

下拉选择

<Select value={this.state.timespanState} onChange={this.handleTimeSpanChange}>

handleTimeSpanChange = (event) => {
        this.setState({ timespanState: event.target.value });
    };

constructor(props) {
        super(props);
        this.state = { timespanState: 'Today'};
        this.handleTimeSpanChange = this.handleTimeSpanChange.bind(this);
    }

【问题讨论】:

  • want to avoid this unnecessary re-render 为什么要这样做?您是否看到性能问题?你看到逻辑错误了吗?
  • @Adam 因为这是不必要的重新渲染,我希望在单击“应用”按钮后更新图表
  • 从用户体验的角度来看,如果应用按钮所做的只是重新渲染图表,您可能应该去掉应用按钮,因为您让用户无缘无故地再次点击。其次,而不是shouldComponentUpdate,这是一个错误陷阱,您应该只传递“应用”值。这可以通过添加第二个状态字段appliedTimeSpan 并在用户单击应用按钮并将appliedTimeSpan 传递给图表组件时更新它来完成。 使用shouldComponentUpdate 控制渲染是不好的做法(从我的角度来看),因为错误的可能性很高。
  • @Adam 我也意识到 shouldComponentUpdate 在我的情况下不是一个好的解决方案。因为一方面我不想重新渲染图表,另一方面我想在时间跨度下拉列表更改时重新渲染它。因此,很难控制
  • 你能发布更多的组件代码吗,听起来appliedTimeSpan 的第二个状态字段肯定会解决你的问题。

标签: javascript reactjs state rerender


【解决方案1】:

使用shouldComponentUpdate 是正确的,只是第一个参数是nextProps,第二个是nextState,所以在你的情况下,undefined 值实际上是nextProps名字不对。

把你的代码改成这个,

shouldComponentUpdate(nextProps,nextState) { // <-- tweak this line
        if (this.state.timespanState !== nextState.timespanState) {
            return true;
        }
        
        return false;
    }

【讨论】:

  • 谢谢,您的回答有效,但现在还有一个小问题:下拉菜单不显示所选项目(因为它返回 false,因此不会重新渲染),它一直显示“今天' 而在调试中,timespanState 已经更改为 'Yesterday',例如
【解决方案2】:

最后,我通过将下拉选择框和图表分成两个独立的组件来解决问题,并将下拉组件作为其父组件图表组件的子组件。 原因是下面的说法

只要状态或道具发生变化,React 组件就会自动重新渲染。

因此,React 将重新渲染该组件的 render() 方法中的所有内容。因此,将它们保存在两个单独的组件中将使它们重新渲染而不会产生副作用。就我而言,过滤器组件中下拉菜单或其他状态的任何状态更改,只会导致该组件内的重新渲染。然后通过回调函数将更新后的状态传递给图表组件。

如下所示:

子组件

export class Filter extends Component {

  handleApplyChanges = () => {
    this.props.renderPieChart(data);
  }
  
  render(){
    return (
      ...
      <Button onClick={this.handleApplyChanges} />
    );
  }
}

父组件

export class Charts extends Component{
      constructor(props){
        this.state = { dataForPieChart: []};
        this.renderPieChart = this.renderPieChart.bind(this);
      }
      
      renderPieChart = (data) => {
            this.setState({ dataForPieChart: data });
      }
      
      render(){
        return (
          <Filter renderPieChart={this.renderPieChart} />
          <Chart>
            ...data={this.state.dataForPieChart}
          </Chart>
        );
      }
    }

如果还有任何问题、分歧或建议,请告诉我:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-05
    • 2018-02-22
    • 1970-01-01
    • 2018-07-14
    • 2017-11-15
    • 1970-01-01
    • 2023-03-26
    • 2019-01-13
    相关资源
    最近更新 更多