简体   繁体   中英

How can you trigger a rerender of a React js component every minute?

The Context:
A hook is defined and returns an object that contains the timestamp of the last time a file was modified.

I calculate the difference from the timestamp until now to show the user how long it was been since they have last saved.

const StageFooter = (props) => {
  const [, , meta] = useMetadata("Tenant Setup Data", "setupData")

  return (
    <StageControls>
      <div id="footer-start"></div>
      <SavingBlock key={meta?.modified}>
        {`Last saved ${
          meta.modified !== undefined ? formatDistanceToNow(meta.modified) : " "
        } ago`}
      </SavingBlock>
      <div id="footer-end"></div>
    </StageControls>
  )
}

export default StageFooter


The Problem:
The calculated difference from the timestamp until now does not update in real-time. For example, it would say "Last saved 10 minutes ago" but after a couple of minutes has passed the string still remains the same. It would only update if the user navigates away from the page then back or if the user refreshes the page.

With all this in mind, I'm basically looking to rerender the component every time a minute has passed so that the value is updated in real-time.

Thanks for your time!

You can create a effect that calls setTimeout every minute and when displaying the time, just subtract from the date.

You should also make a separete component for this, so if you use this inside a component, it won't rerender the hole component "every minute" and only rerender the text "x minutes since last change"

const [fakeCurrentDate, setFakeCurrentDate] = useState(new Date()) // default value can be anything you want

useEffect(() => {
    setTimeout(() => setFakeCurrentDate(new Date()), 60000)
}, [fakeCurrentDate])

...

{/* display time passed since*/}
<div>{fakeCurrentDate - modifiedDate}</div>

Working codesandbox (you will need to wait a minute to see changes)

But as Sterling Archer said in the comments, is this good? Well... who knows?


An advice

Another approach for this would be show a message Updated at XX:XX time instead of showing to the user how many minutes has passed. But this is much more about UX than the technology

I suggest keeping track of the time passed since the initial mount of the component in a state and updating it with an interval. We then display the time passed considering the initial value and adding the time passed since that initial value was received (since the component was mounted).

export const Time = () => {
    // This would be the initial time. We can get it from a hook
    // (meta.modified in your case) or for this example from a ref.
    // I'm setting this to 2000 meaning it was updated 2 seconds ago.
    const initial_time = useRef(2000);
    const [time_passed, setTimePassed] = useState(0);

    useEffect(() => {
        const interval_time = 1000;

        // Set an interval that will update every interval_time
        const myInterval = setInterval(
            () => setTimePassed(time => time + interval_time),
            interval_time
        );

        // Clear the interval when the component unmounts
        return () => clearInterval(myInterval);
    }, []);

    return initial_time.current + time_passed;
};

In order to display the time passed in a friendly way check this other question .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM