在React中使用requestAnimationFrame

时间:2018-09-06 22:05:23

标签: reactjs react-native

我是新来的响应本机的人,我正在尝试优化性能。

我的Touch事件非常缓慢,我正在经历RN documentation on performance,在本示例中他们提到使用 requestAnimationFrame

handleOnPress() {
  // Always use TimerMixin with requestAnimationFrame, setTimeout and
  // setInterval
  this.requestAnimationFrame(() => {
    this.doExpensiveAction();
  });
}

现在,这个描述听起来很模糊,让我难以理解它的用法

就像,我的RN应用中有这个可触摸的事件

<TouchableWithoutFeedback   onPress={() => this.touched(this.props.coinShortName)}>

哪个调用此方法

 touched = (id) => {

        this.setState({selectedPostId: id})
        if (this.props.coinShortName == this.state.selectedPostId ) { 
           this.setState({stateToDisplay: !this.state.stateToDisplay})
        }
    }

问题:有人可以告诉我如何/应该在我的应用程序中使用它吗?

3 个答案:

答案 0 :(得分:6)

我将把我的评论转换成答案,以便我可以更好地设置其格式,并希望将来能对某人有所帮助。我不明确建议将答案标记为正确,但我认为此答案应与该问题一起出现。

本文应为您提供有关requestAnimationFramehttp://www.javascriptkit.com/javatutors/requestanimationframe.shtml的一些背景知识。

我建议阅读上面链接的文章,然后再阅读答案。

我将明确地提到requestAnimationFrame看起来可能与setTimeout(() => {}, 0)类似,但是如果您是1985年生产的Zack Morris手机,那么它的“尽快”可能会在5秒钟后出现,因此使您的动画看起来很糟糕,类似于您的角色在视频游戏中落在屏幕上时。该函数可能在正确的时间被调用,但实际上并没有在正确的时间执行。

想象收集阶段和渲染阶段可能会有所帮助。对不起,我不知道这些东西的确切术语,但是我认为在20 FPS时人眼可以看到平稳的运动,但这意味着您有20个“帧”,所以就像计算20次。这就像收集一群孩子,然后每秒将他们推入公交车20次。将它们推入总线是一个事件,它类似于重新绘制屏幕。有时,孩子们可能会被抛在后面,而下次还会有更多的孩子来接孩子,因此您可以想象随着时间的流逝,人们感觉到的顺畅程度会有所提高。

重要的是要注意,正在针对下一次重绘或下一次屏幕“更改”进行优化。 requestAnimationFrame确实在幕后工作,以确保动画在正确的时间发生并且是平滑的,这意味着像素是在正确的时间应该放置的位置。 (我认为,如果您查看“什么是简陋的动画”的定义,并查看有关该主题的一些讨论,您将会得到很多含义。之所以提及,是因为我们想了解更多有关重新绘制过程以及什么内容的信息。种事情很重要,为什么?

我记得requestAnimationFrame可能会抛弃为时已晚的计算。例如,如果单击按钮,则像素从0%到25%到50%到75%到100%(某些任意距离计算)。我们可以说1秒钟之后,像素应该移动了50%的距离,而2秒钟之后,像素应该到达了100%的最终静止位置。

更重要的是,像素必须在正确的时间放置在正确的位置,而不是将像素精确地移动到应该到达的每个位置。 requestAnimationFrame正在帮助您做到这一点。如果屏幕将要重新粉刷,并且“它”需要运行会花费很长时间的计算,则“它”将忽略它并跳到下一帧。这就像修剪脂肪以保持步伐一致,因此请避免过时。

requestAnimationFrame是解决相同挑战的解决方案,无论是在您的Web浏览器中还是在iOS或Android中。他们都反复进行绘制屏幕的过程。您可以开始计算下一次重画所需的内容,但是开始得太晚了,因此在下一次重画发生时还没有完成。

想象一下您的动画很流畅,但是您的手机突然收到20条推送通知,使CPU陷入瘫痪,导致动画延迟16.7 millisecondsrequestAnimationFrame并没有使像素在错误的时间显示在正确的位置,而是通过使像素在正确的时间位于正确的位置来提供帮助,但这样做可能会产生一些魔力,甚至有时甚至不会尝试绘制像素。否则,可以节省性能并提高感知的平滑度。

我刚刚意识到这是一堵文字墙,但是我认为这将是信息性的。

这些重绘大约每秒发生60帧,因此requestAnimationFrame在计算出最佳时间时可能每秒发生60次触发。 1秒内有1000毫秒,因此60 16.7ms每1帧为一帧。如果人眼感知到20FPS的平滑度,则意味着理论上您可以每45毫秒或30%进行一次重绘,并且动画仍将是平滑的。

我的定义可能不准确,但我希望它们可以帮助您了解正在发生的事情。

答案 1 :(得分:1)

如前所述,您需要将昂贵的操作包装在requestAnimationFrame的实例中。

用法

<TouchableWithoutFeedback onPress={() => this.touched(this.props.coinShortName)}>

touched = (id) => {
  requestAnimationFrame(() => {
    this.setState({selectedPostId: id})
    if (this.props.coinShortName == this.state.selectedPostId ) {
     this.setState({stateToDisplay: !this.state.stateToDisplay})
    }
  });
}

答案 2 :(得分:0)

<TouchableWithoutFeedback onPress={this.handlePress}>

handlePress = () => {
   this.requestAnimationFrame(() => {
     this.touched(this.props.coinShortName)
   });
}

如果您通过直接在内部使用id来删除touched函数中无用的this.props.coinShortName参数,则可以写出更好的事件

handlePress = () => {
   this.requestAnimationFrame(this.touched);
} 

无论如何,touched函数似乎并不昂贵,所以我不知道它是否可以解决您的性能问题