Как упростить setTimeout в ReactJS - PullRequest
       27

Как упростить setTimeout в ReactJS

0 голосов
/ 18 января 2019

Была анимация набора текста на чистом 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?

Полный код ? https://codesandbox.io/s/qk4591q1kw

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Да, вы действительно можете создавать функции, которые действуют как таймер: он возвращает обещание, которое разрешается по истечении времени, что-то вроде этого:

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(), это будет выглядеть следующим образом:

  1. Вы хотите начать с typingEffect
  2. Как только 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

0 голосов
/ 18 января 2019

Обычная практика - использовать для этого Обещания . Вы можете создать вспомогательный Promise, который будет использовать requestAnimationFrame, и сделать ваш поток плоским и «доступным», добавив успешные обратные вызовы onResolve.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...