Каков «правильный» способ обновления реагирующего компонента после интервала с перехватами? - PullRequest
0 голосов
/ 25 января 2019

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

РЕДАКТИРОВАТЬ : для ясности - этот компонент вызывает moment(timepoint).fromNow() в функции formatTimeString ( документы здесь ), поэтому обновление несовершенно ненужно, я обещаю!

У меня ранее было:

const FromNowString = ({ timePoint, ...rest }) => {
  const [text, setText] = useState(formatTimeString(timePoint));

  useEffect(() => {
    setText(formatTimeString(timePoint));
    let updateInterval = setInterval(
      () => setText(formatTimeString(timePoint)),
      30000
    );
    return () => {
      clearInterval(updateInterval);
    };
  }, [timePoint]);

  // Note the console log here is so we can see when renders occur
  return (
    <StyledText tagName="span" {...rest}>
      {console.log('render') || text}
    </StyledText>
  );
};

Это «работает» - компонент корректно обновляется, если изменяется реквизит, и компонент обновляется через каждый интервал, однако при монтировании и при изменении реквизита компонент будет визуализироваться дважды.

Это связано с тем, что useEffect запускает после визуализации, которая возникает при изменении значения timePoint, ивнутри моего useEffect обратного вызова я немедленно вызываю setState метод, который запускает дополнительный рендеринг.

Очевидно, что если я удалю этот вызов к setText, компонент не изменится, когда пропизменения (до тех пор, пока не закончится интервал), потому что text остается прежним.

Я наконец-то понял, что могу запустить рендеринг, установив переменную состояния, которая мне на самом деле не нужна, например:

const FromNowString = ({ timePoint, ...rest }) => {
  // We never actually use this state value
  const [, triggerRender] = useState(null);

  useEffect(() => {
    let updateInterval = setInterval(() => triggerRender(), 30000);
    return () => {
      clearInterval(updateInterval);
    };
  }, [timePoint]);

  return (
    <StyledText tagName="span" {...rest}>
      {console.log("render") || formatTimeString(timePoint)}
    </StyledText>
  );
};

Это работает отлично, компонент рендерит только один раз, когда он монтируется, и один раз, когда меняется пропеллер timePoint, но он чувствует себя хакером.Это правильный путь, или я что-то упускаю?

1 Ответ

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

Я думаю, что этот подход кажется хорошим.Основное изменение, которое я бы сделал, - это на самом деле каждый раз менять значение, чтобы оно было вместо:

const FromNowString = ({ timePoint, ...rest }) => {
  const [, triggerRender] = useState(0);

  useEffect(() => {
    const updateInterval = setInterval(() => triggerRender(prevTriggerIndex => prevTriggerIndex + 1), 30000);
    return () => {
      clearInterval(updateInterval);
    };
  }, [timePoint]);

  return (
    <StyledText tagName="span" {...rest}>
      {console.log("render") || formatTimeString(timePoint)}
    </StyledText>
  );
};

У меня есть две причины для предложения об этом изменении:

  • Я думаюэто поможет при отладке и / или проверке точного поведения, которое происходит.Затем вы можете посмотреть на это состояние в инструментах разработчика и точно узнать, сколько раз вы инициировали повторную визуализацию таким образом.
  • Другая причина - просто дать людям, которые смотрят на этот код больше уверенности в том, что он будетна самом деле делать то, что он должен делать.Даже если setState надежно запускает повторную визуализацию (и React вряд ли изменит это, поскольку она слишком сильно сломается), было бы разумно, чтобы кто-то, взглянув на этот код, задумался: «Гарантирует ли React повторную визуализацию, если setState вызов не приводит к каким-либо изменениям в состоянии? "Основная причина setState всегда вызывает повторную визуализацию, даже если она не изменилась, из-за возможности вызова setState после выполнения мутаций в существующем состоянии, но если существующее состояние равно нулю и ничего не передается в установщик,это был бы случай, когда React мог бы знать, что состояние не изменилось с момента последнего рендеринга, и оптимизировать его.Вместо того, чтобы заставлять кого-то копаться в точном поведении React или беспокоиться о том, может ли это поведение измениться в будущем, я бы действительно изменил состояние.
...