在不渲染的情况下每秒更新当前时间

时间:2020-08-13 23:02:06

标签: reactjs

我在React Native应用程序中的许多组件都要求知道当前时间是每秒。这样,我可以显示更新的实时信息。

我创建了一个简单的功能来使用new Date()设置状态,但是每当设置状态时,组件都会重新渲染,这很浪费我的情况。 这是我所拥有的:

...

export default function App() {
  const [currentDateTime, setCurrentDateTime] = useState(() => new Date().toLocaleString());
  useEffect(() => {
    const secondsTimer = setInterval(() => {
      setCurrentDateTime(new Date().toLocaleString());
    }, 1000);
    return () => clearInterval(secondsTimer);
  }, [setCurrentDateTime]);
  console.log('RENDERING');
  <Text>{currentDateTime}</Text>
  ...

我可以看到控制台日志每秒在渲染。

有没有一种方法可以避免这种重新渲染并仍然更新currentDateTime

3 个答案:

答案 0 :(得分:0)

如果我理解您的意思,那么您想在不触发React生命周期的情况下更新DOM。可以使用refs(请参阅React.useRef):

import * as React from "react";
import "./styles.css";

export default function App() {
  const dateTimeRef = React.useRef<HTMLSpanElement>(null);

  console.log("RENDERING");

  React.useEffect(() => {
    const secondsTimer = setInterval(() => {
      if (dateTimeRef.current) {
        dateTimeRef.current.innerText = new Date().toLocaleString()
      }
    }, 1000);
    return () => clearInterval(secondsTimer);
  }, []);

  return <span ref={dateTimeRef} />;
}

查看工作演示-https://codesandbox.io/s/nice-snow-kt500?file=/src/App.tsx


更新1

如果您要使用Text之类的组件,则该组件将必须将引用转发到dom,例如:

import * as React from "react";
import "./styles.css";

const Text = React.forwardRef<HTMLSpanElement>((props: any, ref) => {
  console.log("RENDERING TEXT")
  return <span ref={ref}></span>
});

export default function App() {
  const dateTimeRef = React.useRef<HTMLSpanElement>(null);

  console.log("RENDERING APP");

  React.useEffect(() => {
    const secondsTimer = setInterval(() => {
      if (dateTimeRef.current) {
        dateTimeRef.current.innerText = new Date().toLocaleString();
      }
    }, 1000);
    return () => clearInterval(secondsTimer);
  }, []);

  return <Text ref={dateTimeRef} />;
}

查看工作演示-https://codesandbox.io/s/jolly-moon-9zsh2?file=/src/App.tsx

答案 1 :(得分:0)

考虑使用shouldComponentUpdate生命周期方法;目的是防止不必要的渲染。添加此方法,并告诉您的组件不要更新状态的这一特定部分。例如,您可以添加此shouldComponentUpdate()来拒绝超过

的更新
// Example logic for only re-rendering every 5 seconds; Adapt as needed.
shouldComponentUpdate(nextProps, nextState) {
  if (this.lastUpdatedTimeInSeconds+5 >= nextState.timeinseconds) {
    return false;
  }
  this.lastUpdatedTimeInSeconds = nextState.timeinseconds
  return true;
}

进一步阅读:https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/using_should_component_update.html

答案 2 :(得分:0)

Eliya Cohen的回答在概念上是正确的。为了避免重新渲染,我们不能使用带间隔的状态。我们需要引用该元素。不幸的是,我无法以相同的方式将Eliya的React代码用于React Native,所以我做了更多的挖掘工作,并在directly manipulating React Native components上找到了文档。 简而言之,您可以操纵内置RN组件的PROPS,并通过不更改状态来避免重新渲染。 由于<Text>组件未使用道具来设置其值,例如<Text text="my text" />,因此我们无法使用此方法来更新它。但是,有效的方法是更新TextInput的值,因为它是由value道具设置的。为了使<TextInput><Text>一样,我们要做的就是将其属性editable设置为false,当然要避免使用默认样式来使其看起来像输入

这是我的解决方案。如果有人有更好的建议,请提出建议。

import React, { useEffect } from 'react';
import { TextInput } from 'react-native';

const Timer: React.FC = () => {
  updateTime = (currentTime) => {
    time.setNativeProps({ text: currentTime });
  };

  useEffect(() => {
    const secondsTimer = setInterval(() => {
      updateTime(new Date().toLocaleString());
    }, 1000);
    return () => clearInterval(secondsTimer);
  }, []);

  return <TextInput ref={(component) => (time = component)} editable={false} />;
};

export default Timer;