在使用钩子间隔之后更新反应组件的“正确”方法是什么?

时间:2019-01-25 11:55:21

标签: reactjs react-hooks

我使用的是反应支持挂钩的alpha版本,并且想要验证我在间隔后没有更新的情况下更新组件文本的方法,而不需要更改道具时所需的次数

  

编辑:为清楚起见,该组件正在moment(timepoint).fromNow()函数(docs here)中调用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>
  );
};

“有效”-如果道具发生更改,组件会正确更新,并且组件会在每个间隔更新,但是,并且在道具发生更改时,组件会渲染两次。

>

这是因为useEffecttimePoint的值更改时在之后运行渲染,并且在我的useEffect回调中,我立即调用了setState方法可触发其他渲染。

很明显,如果我删除对setText的调用,则当prop更改时(直到间隔运行),该组件似乎没有更改,因为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道具更改时仅渲染一次,但是感觉很hack。这是处理事情的正确方法,还是我缺少什么?

1 个答案:

答案 0 :(得分:1)

我认为这种方法看起来不错。我要进行的主要更改是每次实际更改值,以使其改为:

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,但是如果现有状态为null并且未传递任何内容,对于设置人员,在这种情况下,React 可以知道自上次渲染以来状态没有改变并对其进行优化。我不会强迫某人研究React的确切行为,也不担心这种行为将来是否会改变,我会对状态进行实际更改。