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