Я использую альфа-версию обработчиков, поддерживающих реакцию, и хочу проверить свой подход к обновлению текста в компоненте после интервала без рендеринга компонента больше раз, чем необходимо, при изменении свойства.
РЕДАКТИРОВАТЬ: для ясности - этот компонент вызывает
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
, но это выглядит хакерским. Это правильный подход или я что-то упускаю?