【问题标题】:How to re-render a component on each of multiple state changes?如何在多个状态更改中的每一个上重新渲染组件?
【发布时间】:2020-10-18 17:55:56
【问题描述】:

我还在学习 JS/React,所以很可能我做错了。欢迎任何批评。

我有一个画布,上面有一幅画。我想在按下按钮时多次更改绘图的颜色。 明确一点:我想单击按钮多次更改绘图的颜色。

我尝试了几种不同的方法,但它们基本上是两种方法的变体:

  • 当按钮被按下时,它会调用多次改变状态的方法,但 React 只需要渲染我设置的最后一个状态。 (这是有道理的)

  • 对每个setState 使用setTimeout,但它似乎破坏了方法,并且渲染永远不会改变。

这是一个示例代码:

import React from 'react';

class App extends React.Component {
 constructor(props) {
      super(props);
      this.state = {
        color: "#000000",
      }
      this.changeColors = this.changeColors.bind(this);
  }
  
  changeColors() {
    let colors = ["#000000", "#0000FF", "#FF0000", "#00FF00"];
    for (let nextColor in colors) {
      console.log(`Color now ${colors[nextColor]}`);
      // This seems to break it
      //setTimeout(function(){ this.setState({color: colors[nextColor]}); }, 3000);

      // This only renders last state
      this.setState({color: colors[nextColor]});
    }
  }

  render() {
    return (
      <div className="App">
        <h1>Change Colors</h1>
        <MyButton changeColor={this.changeColors}/>
        <MyCanvas color={this.state}/>
      </div>
    );
  }
}

class MyButton extends React.Component {
  render() {
    return (
      <button 
        type="button" 
        className="btn btn-secondary" 
        onClick={() => this.props.changeColor()}>
        Color
      </button>
    );
  }
}

class MyCanvas extends React.Component {
  componentDidMount() {
      this.drawOnCanvas(this.props.color)
  }
  
  componentDidUpdate() {
      this.drawOnCanvas(this.props.color)
  }
  
  drawOnCanvas(color) {
    const ctx = this.refs.canvas.getContext('2d');
    ctx.clearRect(0, 0, 300, 300) 
    ctx.fillStyle=color.color;
    ctx.fillRect(10, 10, 100, 100);
  }
  
  render() {
    return (
      <canvas id="canvas" ref="canvas" width={300} height={300}/>
    );
  }
}

export default App;

我做错了什么,如何通过反应实现多种颜色变化?

【问题讨论】:

  • changeColors 是一个事件处理程序,因此函数执行时发生的所有 setState 调用都是批处理的,因此只会导致一次重新渲染。当您将其置于超时状态时,setState 会在 changeColors 完成执行后被调用,并且每个 setState 都会导致渲染。您应该向 setTimeout 提供箭头函数,以便正确设置 this 的值。

标签: javascript reactjs setstate


【解决方案1】:

如果没有setTimeout,所有的渲染基本上都会合并为一个,这就是 React 的工作原理。但是,您可以尝试使用动态超时的 setTimeout

class App extends React.Component {
 constructor(props) {
      super(props);
      this.state = {
        color: "#000000",
      }
  }
  
  changeColors = () => {
    let colors = ["#000000", "#0000FF", "#FF0000", "#00FF00"];
    colors.forEach((color, i) => {
      setTimeout(() => {
          this.setState({ color });
      }, 500 * i);
    });
  }

  render() {
    return (
      <div className="App" style={{ color: this.state.color }}>
        <h1>Change Colors</h1>
        <button onClick={this.changeColors}>change</button>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>

【讨论】:

  • 谢谢。 您介意跟进吗? 如果colors 是由生成器函数定义的呢?在实际应用中是这种情况,在这种情况下我不能使用colors.forEach。示例:function* getColors() { let colors = ["#000000", "#0000FF", "#00FF00"]; for (let c in colors) yield colors[c] }
  • @ZeCarioca 如果你真的想要发电机 - codesandbox.io/s/…
猜你喜欢
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 2023-03-20
  • 1970-01-01
  • 2020-06-28
  • 2019-06-13
相关资源
最近更新 更多