Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/430.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用setState和类名以不可预知的方式更新DOM_Javascript_Reactjs_Css Animations_React Jsx_Requestanimationframe - Fatal编程技术网

Javascript 使用setState和类名以不可预知的方式更新DOM

Javascript 使用setState和类名以不可预知的方式更新DOM,javascript,reactjs,css-animations,react-jsx,requestanimationframe,Javascript,Reactjs,Css Animations,React Jsx,Requestanimationframe,我正在尝试用React和CSS类制作动画。我已经创建了一个,如果您访问它并单击开始按钮,您将看到文本一个接一个地淡入淡出。这是我想要的动画 然而,当您多次点击Start时,似乎存在一致性问题,我无法指出原因 问题:下面是该问题的记录,您可以看到数字1的行为不符合预期 该过程:单击开始将取消以前的任何requestAnimationFrame'并将状态重置为初始形式。然后,它调用showSegments()函数,该函数的干净状态没有附加任何类名 然后,此函数映射整个状态,并将isActive添

我正在尝试用React和CSS类制作动画。我已经创建了一个,如果您访问它并单击开始按钮,您将看到文本一个接一个地淡入淡出。这是我想要的动画

然而,当您多次点击Start时,似乎存在一致性问题,我无法指出原因

问题:下面是该问题的记录,您可以看到数字1的行为不符合预期

该过程:单击开始将取消以前的任何requestAnimationFrame'并将状态重置为初始形式。然后,它调用showSegments()函数,该函数的干净状态没有附加任何类名

然后,此函数映射整个状态,并将
isActive
添加到状态中的每个段。然后,我们用一个映射渲染dom并应用新状态

这将创建一个平滑的分段动画,因为每个类都会被逐个删除。然而,当我在Chrome(56.0.2924.87版本(64位))和iOS上测试时,它是非常不一致的,有时它工作得很好,其他时候第一个DOM元素不会动画,它只会保持在“isActive”状态,并可见它的完成转换状态

我试图在safari中复制这个问题,但效果非常好,我还没有反应过来,所以我不确定这是否是处理问题的最佳方式,希望有人能提供一些见解,解释为什么这个行为非常不稳定

/* MotionText.js */
import React, { Component } from 'react';
import shortid from 'shortid';

class MotionText extends Component {
  constructor(props) {
    super(props);

    this.showSegments = this.showSegments.bind(this);
    this.handleClickStart = this.handleClickStart.bind(this);
    this.handleClickStop = this.handleClickStop.bind(this);

    this.initialState = () => { return {
      curIndex: 0,
      textSegments: [
        ...'123456789123456789123456789123456789'
      ].map(segment => ({
        segment,
        id: shortid.generate(),
        className: null
      }))
    }};
    this.state = this.initialState();
  }

  handleClickStop() {
    cancelAnimationFrame(this.rafId);
  }

  handleClickStart(){
    cancelAnimationFrame(this.rafId);

    this.setState(this.initialState(), () => {
      this.rafId = requestAnimationFrame(this.showSegments);
    });
  }

  showSegments() {
    this.rafId = requestAnimationFrame(this.showSegments);

    const newState = Object.assign({}, this.state);
    newState.textSegments[this.state.curIndex].className = 'isActive';

    this.setState(
      {
        ...newState,
        curIndex: this.state.curIndex + 1
      },
      () => {
        if (this.state.curIndex >= this.state.textSegments.length) {
          cancelAnimationFrame(this.rafId);
        }
      }
    );

  }

  render(){
    const innerTree = this.state.textSegments.map((obj, key) => (
      <span key={obj.id} className={obj.className}>{obj.segment}</span>
    ));

    return (
      <div>
        <button onClick={this.handleClickStart}>Start</button>
        <button onClick={this.handleClickStop}>Stop</button>
        <hr />
        <div className="MotionText">{innerTree}..</div>
      </div>
    )
  }
}

export default MotionText;
/*MotionText.js*/
从“React”导入React,{Component};
从“shortid”导入shortid;
类MotionText扩展组件{
建造师(道具){
超级(道具);
this.showSegments=this.showSegments.bind(this);
this.handleClickStart=this.handleClickStart.bind(this);
this.handleClickStop=this.handleClickStop.bind(this);
this.initialState=()=>{return{
库林德斯:0,
文本段:[
...'123456789123456789123456789123456789'
].map(段=>({
段
id:shortid.generate(),
类名:null
}))
}};
this.state=this.initialState();
}
handleClickStop(){
取消动画帧(this.rafId);
}
handleClickStart(){
取消动画帧(this.rafId);
this.setState(this.initialState(),()=>{
this.rafId=requestAnimationFrame(this.showSegments);
});
}
showSegments(){
this.rafId=requestAnimationFrame(this.showSegments);
const newState=Object.assign({},this.state);
newState.textSegments[this.state.curIndex].className='isActive';
这是我的国家(
{
…新闻状态,
curIndex:this.state.curIndex+1
},
() => {
if(this.state.curIndex>=this.state.textSegments.length){
取消动画帧(this.rafId);
}
}
);
}
render(){
const innerTree=this.state.textSegments.map((对象,键)=>(
{obj.段}
));
返回(
开始
停止

{innerTree}。。 ) } } 导出默认运动文本;
谢谢您的时间,如果有任何问题,请询问


将方法更改为类似的方式很有效

render(){
    let d = new Date();
    const innerTree = this.state.textSegments.map((obj, key) => (
      <span key={d.getMilliseconds() + obj.id} className={obj.className}>{obj.segment}</span>
    ));

    return (
      <div>
        <button onClick={this.handleClickStart}>Start</button>
        <button onClick={this.handleClickStop}>Stop</button>
        <hr />
        <div className="MotionText">{innerTree}..</div>
      </div>
    )
  }
render(){
设d=新日期();
const innerTree=this.state.textSegments.map((对象,键)=>(
{obj.段}
));
返回(
开始
停止

{innerTree}。。 ) }

这样做的好处是,该关键点与之前为渲染的第一个跨度指定的关键点不同。任何使关键点不同于上一个关键点的方法都将有助于创建此动画。否则React将不会再次渲染它,因此您将永远不会在动画中看到这一点。

有趣的是,我尝试了建议的代码,但它有一种奇怪的效果,即根本不显示css动画,我想知道这是否是因为React正在渲染附加了类的子级,而不是将类应用于现有子级。。。当我在同一个窗口中保存代码时,它起作用了。是的,你是对的,动画在这之后丢失了。你可以使用在数字前添加空格的方法。类似于“123456789123456789123456789123456789123456789123456789”的代码。因为只有第一个跨度仍然存在,这不起作用。哈哈,我实际上也尝试过这种方法,到目前为止,我提出的最佳解决方案是将函数放入setTimeout,设置状态和调用第一个requestAnimationFrame之间的延迟似乎给了它足够的时间。我仍然不确定这是否是最好的方式,但是…我有一个随机的灯泡时刻,我已经制定出一个解决方案并发布了答案,感谢您提供了对React键的洞察,如果没有这个,我不可能制定出它!这个键——不是双关语——是在生成/重置组件时设置一个唯一的键,我使用了初始状态,将它放入处理程序也就足够了。谢谢你的帮助!