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

Ed *_*ffe 6 reactjs react-hooks

我正在使用 alpha 版本的 react 支持钩子,并希望验证我在一段时间后更新组件中文本的方法,而不会在 prop 更改时渲染组件超过所需次数。

编辑:为了清楚起见 - 此组件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>
  );
};
Run Code Online (Sandbox Code Playgroud)

这“有效” - 如果 props 更改,组件会正确更新,并且组件会在每个时间间隔更新,但是在安装时,当 prop 更改时,组件将渲染两次。

这是因为在值更改时导致的渲染之后useEffect运行,并且在我的回调中我立即调用timePointuseEffectsetState触发额外渲染的方法。

显然,如果我删除对 的调用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>
  );
};
Run Code Online (Sandbox Code Playgroud)

这工作得很好,组件只在挂载时渲染一次,并且在timePointprop 改变时渲染一次,但感觉很糟糕。这是处理事情的正确方式,还是我遗漏了什么?

Rya*_*ell 4

我认为这个方法似乎不错。我要做的主要更改是每次实际更改该值,因此它是:

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>
  );
};
Run Code Online (Sandbox Code Playgroud)

我建议进行此更改有两个原因:

  • 我认为这在调试和/或验证正在发生的确切行为时会有帮助。然后,您可以在开发工具中查看此状态,并准确查看以这种方式触发重新渲染的次数。
  • 另一个原因只是为了让查看这段代码的人更有信心,相信它实际上会完成预期的任务。尽管setState可靠地触发了重新渲染(React 不太可能改变这一点,因为它会破坏太多),但对于查看此代码的人来说,有理由想知道“如果调用不保证重新渲染,React 是否会保证重新渲染setState”会导致国家发生任何变化吗?” 即使未更改,也始终会触发重新渲染的主要原因setState是因为setState在对现有状态进行突变后可能会调用,但如果现有状态为 null 并且没有任何内容传递给 setter,则可能会出现以下情况: React可以知道自上次渲染以来状态没有改变并对其进行优化。我不会强迫某人深入研究 React 的确切行为或担心该行为将来是否会改变,而是会对状态进行实际的更改。


归档时间:

查看次数:

518 次

最近记录:

7 年,4 月 前