Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 710
Tyler Turden Avatar asked Feb 28 '20 19:02

Tyler Turden


People also ask

How to force a re-render in react?

4 methods to force a re-render in React 1. Re-render component when state changes Any time a React component state has changed, React has to run the render ()... 2. Re-render component when props change class Child extends React.Component { render() { console.log('Child component:... 3. Re-render ...

How does React React schedule render?

React schedules a render every time state changes (scheduling a render doesn’t mean this happens immediately, this might take time and be done at the best moment). Changing a state means React triggers an update when we call the useState function (useState is a Hook that allows you to have state variables in functional components).

What happens when you update a prop in react?

Update in prop: Likewise the change in prop leads to state change and state change leads to re-rendering of the component by React. Re-rendering of parent component: Whenever the components render function is called, all its subsequent child components will re-render, regardless of whether their props have changed or not.

What triggers a button to rerender?

It triggers a re-render when the state changes. The first time you click the button you change the state from false to true so a rerender is triggered. Subsequent clicks you change it from true to true which isn't a change, so it doesn't. so it actually changes.


2 Answers

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

like image 88
Vencovsky Avatar answered Oct 26 '22 15:10

Vencovsky


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.

like image 37
Alvaro Avatar answered Oct 26 '22 15:10

Alvaro