简体   繁体   English

如何在 React 中为 state 值变化设置动画?

[英]How to animate state value change in React?

I have a PdfViewer dialog in my webapp created in React, it displays pdf-s using this package: https://github.com/wojtekmaj/react-pdf , it has a scale property to define the scale of the pdf viewer component as such: I have a PdfViewer dialog in my webapp created in React, it displays pdf-s using this package: https://github.com/wojtekmaj/react-pdf , it has a scale property to define the scale of the pdf viewer component as这样的:

<Page pageNumber={pageNumber} scale={scale} height={props.height} />

The scale property is held in a state and is changed by controls on the page. scale 属性保存在 state 中,并由页面上的控件更改。 It is working correctly, the only problem is that it doesn't animate the transition when changing the scale.它工作正常,唯一的问题是它在更改比例时不会为过渡设置动画。 What is the proper way of setting the scale state smoothly?顺利设置刻度 state 的正确方法是什么?

I haven't found such option in their github, so you would need to implement it yourself.我在他们的 github 中没有找到这样的选项,所以你需要自己实现它。

You will need:你会需要:

  • Two state values - one for target scale, and one for current scale.两个 state 值 - 一个用于目标比例,一个用于当前比例。
  • Knowledge of setTimeout setTimeout的知识
  • A bit of arithmetic一点算术

Basic and very slow example:基本且非常慢的示例:

  // initially we set both states to same value
  let [target_scale, set_target_scale] = React.useState(1);
  let [current_scale, set_current_scale] = React.useState(1);
  let [step, set_step] = React.useState(0);

  // we need to get our step. We calculate it when target changes
  React.useEffect(
    function () {
      // step is amount that we want to animate on each frame
      // 1000 is animation duration (in this case it is one second), and 16 is amount of ms to get 60fps
      // 1000 / 16 will give us amount of steps to perform animation. In this case it would be 62.5 frames. Math floor wil make it 62 frames
      // Note that if current_scale is larger then target scale, we will get negative value
      set_step((target_scale - current_scale) / Math.ceil(1000 / 16));
    },
    [target_scale]
  );

  // Now we need and effect that will look for state changes and run our animation
  React.useEffect(
    function () {
      // we don't need it to run if both scales are the same
      // because all numbers in JS are doubles, we want to round it up, to not miss this point
      if (current_scale.toFixed(2) === target_scale.toFixed(2)) return;
      let timeout_id = window.setTimeout(
        () => set_current_scale(current_scale + step),
        16
      );
      return () => window.clearTimeout(timeout_id);
    },
    [target_scale, current_scale, step]
  );

Here is working sample:这是工作示例:

https://jsfiddle.net/136wjope/1/ https://jsfiddle.net/136wjope/1/

Awesome part here is that React will greatly optimize this stuff.这里很棒的部分是 React 将极大地优化这些东西。 Bad part is that it is messy and, probably, buggy.不好的部分是它很乱,而且很可能是错误的。 Also there is no nice easing here.这里也没有很好的缓和。 But at least you know how to do it you need.但至少你知道如何去做你需要的。 So, to not waste work time, I suggest you to use react-spring library.所以,为了不浪费工作时间,我建议你使用react-spring库。 It is velocity based and it makes your animations feel good.它是基于速度的,它让你的动画感觉很好。 Also it can animate arbitrary values, which is also very awesome.它还可以为任意值设置动画,这也非常棒。

Here all the above remade for react-spring: https://codesandbox.io/s/clever-grothendieck-bxo6g?file=/src/App.js以上为 react-spring 重新制作的所有内容: https://codesandbox.io/s/clever-grothendieck-bxo6g?file=/src/App.js

Disclaimer : I have practically zero experience with react-spring, so you definitely should read documentation and look at examples.免责声明:我对 react-spring 的经验几乎为零,因此您绝对应该阅读文档并查看示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM