纯javaScript中有一个打字动画,该动画已转换为ReactJS。 setTimeout
函数看起来不干净,并且没有遵循ReactJS标准的最佳实践。
例如animationManager()
animationManager = () => {
this.rafRef = requestAnimationFrame(time => {
const typingData = this.props.data;
this.typeEffect(time, typingData[this.index], () => {
this.timeoutRef = setTimeout(() => {
this.rafRef = requestAnimationFrame(time => {
this.deleteEffect(time, () => {
this.timeoutRef = setTimeout(() => {
this.index =
this.index === typingData.length - 1 ? 0 : this.index + 1;
this.animationManager();
}, this.props.pauseBeforeRestarting);
});
});
}, this.props.pauseBeforeDeleting);
});
});
};
是否所有这些setTimout
都可以使其变得更加干净?
答案 0 :(得分:1)
是的,您实际上可以创建一个类似于计时器的函数:它会返回一个承诺,该承诺会在时间用尽时得到解决,如下所示:
timer = (duration) => {
return new Promise(resolve => {
window.setTimeout(resolve, duration);
});
}
类似地,您可以对requestAnimationFrame
执行相同的操作。诀窍是使用ES6传播运算符,以便您可以将任意数量的参数传递给要调用的回调:
animationFrame = (callback, ...args) => {
return new Promise(resolve => {
window.requestAnimationFrame(time => {
callback(time, ...args);
});
})
}
由于您使用的是ES6,因此可以在继续执行下一行代码之前,使用async
函数等待计时器完成。如果我们分解您的animationManager()
代码,则代码如下:
typingEffect
开头typingEffect
完成后,您想触发deleteEffect
在这种情况下,我们可以这样重构您的代码:
animationManager = () => {
const deleteFunc = (time, typingData) => {
this.deleteEffect(time, async () => {
await this.timer(this.props.pauseBeforeRestarting);
this.index = this.index === typingData.length - 1 ? 0 : this.index + 1;
this.animationManager();
});
};
const typeFunc = (time) => {
const typingData = this.props.data;
this.typeEffect(time, typingData[this.index], async () => {
await this.timer(this.props.pauseBeforeDeleting);
await this.animationFrame(deleteFunc, typingData);
})
};
this.animationFrame(typeFunc);
};
我已分叉您的示例,以提供稍微重构的代码的概念证明:https://codesandbox.io/s/308kxjzwrq
答案 1 :(得分:0)
通常的做法是使用Promises。您可以创建助手Promise,该助手将使用requestAnimationFrame,并通过在onResolve上添加成功回调来使流程平坦且“可设置”。