为什么不正确更新dom?

时间:2016-07-13 22:52:31

标签: javascript reactjs

我有这个ReactJS类:

import React from 'react';

export default class Test extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      status: 'main',
    };
  }

  applyTransition() {
    this.setState({
      status: 'leaving',
    }, () => {
      setTimeout(() => {
        this.setState({
          status: 'entering'
        }, () => setTimeout(() => {
          this.setState({
            status: 'main',
          });
        }, 1000));
      }, 1)
    });
  }
  handleClick() {
    this.applyTransition();
  }
  computeStyle() {
    switch (this.state.status) {
      case 'leaving':
        return {
          transform: 'translate(-100%)',
        };
      case 'entering':
        return {
          transform: 'translate(0%)',
          transition: 'transform 1s',
        };
      case 'main':
        return {
          transform: 'translate(0%)',
        };
    }
  }

  render() {
    const style = this.computeStyle();
    return (
      <div>
        <div style={_.merge({}, style, {
            display: 'flex',
            flexOrientation: 'row',
          })}>
          <div>1</div>
          <div>2</div>
          <div>3</div>
        </div>
        <button onClick={() => this.handleClick()}>Click</button>
      </div>
    );
  }
}

我的工作流程如下,我有一个“主”状态,其中内容正常显示,我有一个“beforeTransition”状态,其中我希望内容被翻译到左边和一个“转换”,其中我希望内容能够通过CSS转换回来。

如果我不使用1毫秒的超时,似乎react不会正确更新DOM。因此,过渡不起作用。为什么呢?

编辑:

那么如何确保我的CSS过渡工作流程完成?我想在我的state.status变量的每次更改时更新并正确呈现DOM。

我不想使用ReactCSSTransitionGroup,因为我想了解如何从头开始创建一些自定义CSS转换。

2 个答案:

答案 0 :(得分:1)

尽管我不太熟悉浏览器中渲染队列的工作方式,但我认为你不能在它们之间没有延迟地分配相反的css属性。就像过渡到左边 - 然后再过右。

它可能与React本身无关。

请看这里:https://jsbin.com/geqogeqifa/edit?html,output

编辑:(大量猜测)
由于渲染输出和JS在浏览器中使用相同的事件队列,因此在“离开”和“输入”css属性赋值之间不会重新渲染 - 这导致最后一个属性在第一个属性被渲染之前覆盖第一个属性

所以我的猜测是,通过使用超时,您在事件队列中插入另一个事件,该事件在上一个渲染事件发生后调用...

伪事件队列:

没有超时:

Event(JS): css(leaving), css(entering)
Event(Render) // renders only entering

超时:

Event(JS): css(leaving), setTimeOut(css(entering))
Event(Render) // renders leaving
Event(timeOut): css(entering)
Event(Render) // renders entering

答案 1 :(得分:0)

如果您只是试图动画翻译现有元素(根据您的代码似乎是这种情况)那么这将是一个更简单的方法:

constructor() {
  super();
  this.state = {enter: false};
}

handleClick() {
  this.setState({
    enter: true
  });
}

computeStyle(enter) {
  return {
    transform: enter ? 'translate(0%)' : 'translate(-100%)',
    transition: 'transform 1s'
  };
}

render() {
  const style = this.computerStyle(this.state.enter);

  // divs and stuff with your style

  <button onClick={this.handleClick} />
}