React.JS:定时状态变化的顺序

时间:2017-06-05 11:42:21

标签: javascript reactjs

我有一个简单的Web应用程序,其中包含一个父组件和三个子组件。孩子们只是div盒子,可以根据他们的属性活动将他们的背景颜色从白色变为红色。 animateChild()功能可用于将特定子项变为红色,然后在1s后再次变为白色。

我的目标是"玩"一个任意的子动画序列,每个动画之间间隔1秒。这应该发生在 animateSequence()函数中。

我最初的想法是在每次迭代时使用for循环并在 window.setTimeout()中调用 animateChild(childNum)。但是,这没有用。我想因为setState()是异步的,并且几个状态更改会合并在一起。

在每个动画之间以1秒的休息时间完成动画序列(例如,儿童1,儿童2,儿童3)的最佳方法是什么?非常感谢你

Javascript代码:

class Child extends React.Component {

  render() {
    var childStyle = "basic"; 
    if (this.props.active){
      childStyle += " active";
    }
    return (
        <div className={childStyle}></div>
    );
  }
}


class Parent extends React.Component {
  constructor(){
    super();
    this.state = {
      firstChildActive:false,
      secondChildActive:false,
      thirdChildActive:false,
    };
    this.animateChild = this.animateChild.bind(this);

  }


  animateChild(childNum){
    var childDict = ["firstChildActive","secondChildActive","thirdChildActive"];
    this.setState({[childDict[childNum]]: true}, function() {

        window.setTimeout(() => {
        this.setState({[childDict[childNum]]: false});

        },1000);
    });
  }

  animateSequence(){
    // animate child 2, then child 1, then child 3, then child 1, etc.
  }

  render() {
    return (
      <div className ="container">
      <Child active={this.state.firstChildActive}/>
      <Child active={this.state.secondChildActive}/>
      <Child active={this.state.thirdChildActive}/>
      </div>
    );
  }
}


ReactDOM.render(<Parent />,document.getElementById('app'));

CSS代码:

.container{
  display:flex;
  width:100%;
  justify-content: space-between;

}

.basic{
  margin: 10px;
  width: 100px;
  height:100px;
  border: 2px solid black;
}

.active{
  background: red;
}

Codepen:https://codepen.io/miga89/full/owgZea/

3 个答案:

答案 0 :(得分:1)

我还将你的子组件转换为无状态组件,解决方案只是使用一个简单的setInterval。

https://codepen.io/anon/pen/LLEyVo

const Child = ({ isActive }) => {
    var childStyle = "basic"; 
    if ( isActive ) childStyle += " active";
    return <div className={ childStyle }></div>
}

class Parent extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      firstChildActive  : false,
      secondChildActive : false,
      thirdChildActive  : false,
    };
  }

  animateSequence(){

    const TOTAL = 3;
    const CHILD_DICT = ["firstChildActive","secondChildActive","thirdChildActive"];

    let run = 0;

    var setActive = setInterval( () => {
      this.setState({ [CHILD_DICT[run]]: true });
      run = run + 1;
      if( run === TOTAL ) {
        clearInterval(setActive);
      }
    }, 1000)

  }

  render() {
    return (
      <div className ="container">
        <button onClick={ () => this.animateSequence() }>Run Sequence</button>
      <Child isActive={this.state.firstChildActive }/>
      <Child isActive={this.state.secondChildActive } />
      <Child isActive={this.state.thirdChildActive }/>
      </div>
    );
  }
}


ReactDOM.render(<Parent />,document.getElementById('app'));

答案 1 :(得分:0)

您的此上下文在第一个setState的回调中无效。

var childDict = ["firstChildActive","secondChildActive","thirdChildActive"];
this.setState({[childDict[childNum]]: true}, function() {

应该是

var childDict = ["firstChildActive","secondChildActive","thirdChildActive"];
this.setState({[childDict[childNum]]: true}, () => {

答案 2 :(得分:0)

如果你想在没有按钮的情况下使用原型中的componentDidMount方法:

 componentDidMount(){
  this.animateSequence();
}
  render() {
    return (
      <div className ="container">        
      <Child isActive={this.state.firstChildActive }/>
      <Child isActive={this.state.secondChildActive } />
      <Child isActive={this.state.thirdChildActive }/>
      </div>
    );
  }