<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Antoine Quinquenel</title>
    <description>The latest articles on Forem by Antoine Quinquenel (@aquinq).</description>
    <link>https://forem.com/aquinq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F426749%2Fb664c79e-57f3-4c0d-ac2b-c3a9406d536a.jpg</url>
      <title>Forem: Antoine Quinquenel</title>
      <link>https://forem.com/aquinq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aquinq"/>
    <language>en</language>
    <item>
      <title>How to schedule an update of a React component in the future</title>
      <dc:creator>Antoine Quinquenel</dc:creator>
      <pubDate>Thu, 30 Jan 2025 09:35:50 +0000</pubDate>
      <link>https://forem.com/wecasa/how-to-schedule-an-update-of-a-react-component-in-the-future-222m</link>
      <guid>https://forem.com/wecasa/how-to-schedule-an-update-of-a-react-component-in-the-future-222m</guid>
      <description>&lt;h3&gt;
  
  
  &lt;code&gt;useRerenderTimeout&lt;/code&gt; &amp;amp; &lt;code&gt;useRerenderInterval&lt;/code&gt; : 2 custom hooks to re-render a React component at a specific time, or at a regular interval of time.
&lt;/h3&gt;

&lt;p&gt;⚡️ In a hurry ? Go directly to the TL;DR section.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;




&lt;p&gt;Most of the time, we develop user interfaces (UI) that react to user interactions.&lt;br&gt;
But what if you need the UI to react to the current time ?&lt;/p&gt;

&lt;p&gt;At Wecasa, we recently needed some content of our React Native app to update automatically at a specific time.&lt;br&gt;
To do so, we created two custom hooks that allow a component to re-render itself at a specific time or at a regular interval of time, with a simple and generic implementation for a great developer experience. ✨&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Trigger a re-render at a specific time
&lt;/h2&gt;

&lt;p&gt;Let's say we want to create a &lt;code&gt;Meeting&lt;/code&gt; component that renders differently depending on whether the meeting has started or not.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Currently, nothing forces the component to change once the meeting starts. This means, if it is displayed at 13:59 and the meeting starts at 14:00, after one minute it will continue showing the meeting as upcoming even though it has started.

&lt;p&gt;To force a re-render of the component, we can simply trigger a state update with a local timer that executes at the meeting's start time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The timer is set via a custom &lt;code&gt;useTimeout&lt;/code&gt; hook, inspired by &lt;a href="https://www.joshwcomeau.com/snippets/react-hooks/use-timeout/" rel="noopener noreferrer"&gt;this article from Josh Comeau&lt;/a&gt;. It's also available in popular hooks libraries, such as &lt;a href="https://www.npmjs.com/package/usehooks-ts" rel="noopener noreferrer"&gt;usehooks-ts&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/@uidotdev/usehooks" rel="noopener noreferrer"&gt;@uidotdev/usehooks&lt;/a&gt;.&lt;br&gt;
We use &lt;code&gt;useReducer&lt;/code&gt; instead of &lt;code&gt;useState&lt;/code&gt; to not bother passing params to the state setter, but naturally &lt;code&gt;useState&lt;/code&gt; works as well.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Now, our &lt;code&gt;Meeting&lt;/code&gt; component already refreshes itself at the meeting's start time automatically! 🎉&lt;br&gt;
But there is still room for improvement, especially in terms of performance ⚡️ and readability 🤓&lt;br&gt;
&lt;br&gt;

&lt;h3&gt;
  
  
  Optimizing the execution
&lt;/h3&gt;

&lt;p&gt;Let’s say the meeting starts at 14:00:00, and the &lt;code&gt;Meeting&lt;/code&gt; component first renders one minute earlier, at 13:59:00.&lt;br&gt;
Now, if the &lt;code&gt;Meeting&lt;/code&gt; component re-renders at 13:59:30 for any reason (for instance, if one of its parent components re-renders), &lt;code&gt;delay&lt;/code&gt; will be recalculated, changing from 60 seconds to 30 seconds.&lt;/p&gt;

&lt;p&gt;As a result, &lt;code&gt;useTimeout&lt;/code&gt; will destroy the current timer and create a new one that will still execute at the same time, 14:00:00, since &lt;code&gt;startsAt&lt;/code&gt; remains unchanged.&lt;br&gt;
To prevent this unnecessary "clean-up", we can memoize &lt;code&gt;delay&lt;/code&gt; so that it only changes when &lt;code&gt;startsAt&lt;/code&gt; is updated.&lt;br&gt;
Also, we don’t want to set a timer if the meeting has already started, so in that case, we set &lt;code&gt;delay&lt;/code&gt; to &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
Now, our &lt;code&gt;Meeting&lt;/code&gt; component will set a single timer throughout its entire lifecycle&lt;br&gt;
(as long as &lt;code&gt;startsAt&lt;/code&gt; remains unchanged), and only if the meeting has not yet started.&lt;br&gt;
&lt;br&gt;

&lt;h3&gt;
  
  
  Encapsulate into a custom hook
&lt;/h3&gt;

&lt;p&gt;Our &lt;code&gt;Meeting&lt;/code&gt; component is becoming difficult to read, and we'd like to extract this logic into a reusable piece of code: we can create a custom &lt;code&gt;useRerenderTimeout&lt;/code&gt; hook that takes the date at which the component should re-render as an argument.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
Since the &lt;code&gt;date&lt;/code&gt; parameter is a dependency of this &lt;code&gt;useMemo&lt;/code&gt;, we want to ensure its reference remains stable across renders. For this reason, we define it as a &lt;code&gt;string&lt;/code&gt; rather than a &lt;code&gt;Date&lt;/code&gt; object.

&lt;p&gt;Then, the &lt;code&gt;Meeting&lt;/code&gt; component would look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
By moving the logic into a custom hook, the &lt;code&gt;Meeting&lt;/code&gt; component only needs a single line of code to re-render itself at the desired time. ✨&lt;br&gt;
This keeps the code light and clear, and offers a generic solution that's easy to use.&lt;br&gt;
&lt;br&gt;

&lt;h2&gt;
  
  
  Trigger multiple re-renders at specific times
&lt;/h2&gt;

&lt;p&gt;Let's say we now want to display a progress bar indicating the remaining time, starting 30 minutes before the meeting begins.&lt;br&gt;
The &lt;code&gt;Meeting&lt;/code&gt; component will now have a third possible status," imminent", in addition to "upcoming" and "started".&lt;br&gt;
This means the component needs to re-render twice: once 30 minutes before the meeting starts, and once when the meeting starts.&lt;br&gt;
To improve code cohesion, we can associate each status with the time at which it ends, which is also the time we want the &lt;code&gt;Meeting&lt;/code&gt; component to re-render.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
When &lt;code&gt;Meeting&lt;/code&gt; mounts, it will set a timeout to trigger a re-render 30 minutes before the meeting starts.&lt;br&gt;
Once this timeout executes, &lt;code&gt;getMeetingStatus&lt;/code&gt; will be called again, returning a new value for &lt;code&gt;status.endsAt&lt;/code&gt;, which will set a new timeout to trigger a re-render at the meeting start time.&lt;br&gt;
This "call loop", based on the component's lifecycle, allows us to handle both re-renders using a single instance of the &lt;code&gt;useRerenderTimeout&lt;/code&gt; hook. 🎉&lt;br&gt;
 &lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;h2&gt;
  
  
  Trigger a re-render at a regular interval of time
&lt;/h2&gt;

&lt;p&gt;The "imminent" status lasts 30 minutes, but we want to avoid running a 30-minute-long animation for the progress bar.&lt;br&gt;
Instead, we refresh the progress bar at 1% increments, which means updating it every 18 seconds.&lt;/p&gt;

&lt;p&gt;While we could use the same "call loop" approach with &lt;code&gt;useRerenderTimeout&lt;/code&gt;, it's simpler in this case to use an interval instead of a timeout, as the time between re-renders is constant.&lt;/p&gt;

&lt;p&gt;We can create a similar hook to &lt;code&gt;useRerenderTimeout&lt;/code&gt; that runs an interval instead of a timeout.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The interval is set via a custom &lt;code&gt;useInterval&lt;/code&gt; hook, inspired by&lt;br&gt;
&lt;a href="https://overreacted.io/making-setinterval-declarative-with-react-hooks/" rel="noopener noreferrer"&gt;this article from Dan Abramov&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Just like we did for &lt;code&gt;useRerenderTimeout&lt;/code&gt;, we use &lt;code&gt;useReducer&lt;/code&gt; instead of &lt;code&gt;useState&lt;/code&gt; to not bother passing params to the state setter, but naturally &lt;code&gt;useState&lt;/code&gt; works as well.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
The interval continues as long as &lt;code&gt;ms&lt;/code&gt; is a positive value, and it stops when &lt;code&gt;ms&lt;/code&gt; is set to &lt;code&gt;null&lt;/code&gt;.&lt;br&gt;
 &lt;br&gt;
Depending on the faith you have in yourself, you may want to add a safeguard to prevent unexpected excessively frequent intervals (recommended).&lt;br&gt;
For example, we chose an arbitrary minimum interval of 1 second.&lt;br&gt;
 &lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
The &lt;code&gt;ProgressBar&lt;/code&gt; component can then use this hook to re-render itself every 18 seconds, independently of the &lt;code&gt;Meeting&lt;/code&gt; component:&lt;br&gt;
 

&lt;blockquote&gt;
&lt;p&gt;Using this hook directly in the &lt;code&gt;Progress&lt;/code&gt; component instead of its parent ensures that the minimum amount of JSX is updated.&lt;br&gt;
In general, these hooks should be used as low as possible in the component tree.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;Every 18 seconds, &lt;code&gt;useRerenderInterval&lt;/code&gt; triggers a re-render,&lt;br&gt;
recalculating &lt;code&gt;remainingPercentage&lt;/code&gt; and automatically updating the relevant UI. ✅&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Managing timers and intervals in React components can be tricky, and can quickly make the code hard to read and to maintain.&lt;br&gt;
Creating these two hooks &lt;code&gt;useRerenderTimeout&lt;/code&gt; and &lt;code&gt;useRerenderInterval&lt;/code&gt; allowed us to easily implement complicated business logics based on timers and intervals in just a few lines of code.&lt;/p&gt;

&lt;p&gt;They take advantage of the component's lifecycle, by triggering re-renders via local state updates, to keep the rest of the component's logic decoupled from its need to refresh at specific times, in a simple and generic way for a great developer experience. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;useRerenderTimeout&lt;/code&gt; hook
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;h4&gt;
  
  
  Use case:
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;h3&gt;
  
  
  &lt;code&gt;useRerenderInterval&lt;/code&gt; hook
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;h4&gt;
  
  
  Use case:
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

</description>
      <category>react</category>
      <category>reacthooks</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
