Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

236
Visualizações
How do trigger a rerender based on a timer but only on a specific component in React

I have a component that renders relative time

import React, { useEffect, useRef, useReducer } from 'react'
import { Text, TextProps } from 'react-native';
import { formatDistanceToNow } from 'date-fns';
type MomentTextProps = Omit<TextProps, 'children'> & {
  date: Date | number;
  pollTimeMs?: number;
}

export function MomentText({
  date,
  pollTimeMs = 60000,
  ...props }: MomentTextProps): JSX.Element {
  const [formatted, update] = useReducer(
    () => formatDistanceToNow(Date.now()),
    formatDistanceToNow(Date.now())
  );
  const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
  function doUpdate() {
    update();
    timeoutRef.current = setTimeout(update, pollTimeMs);
  }
  useEffect(() => {
    doUpdate();
    return () => {
      clearTimeout(timeoutRef.current!);
    };
  });

  return <Text {...props}>{formatted}</Text>
}

Which works, but seems overkill that I am creating so many timeouts, I was wondering if there's a way of doing this via a "React context" but only rerender this one specific child.

The way I am thinking of it (as I type this) is to have a subscribe/notify hook like this...

/**
 * This hook provides a simple subscription semantic to React components.
 */
export function useSubscription<T = unknown>(): SubscriptionManager<T> {
  const subscribersRef = useRef<((data: T) => void)[]>([]);
  function subscribe(fn: (data: T) => void) {
    subscribersRef.current.push(fn);
    return () => {
      subscribersRef.current = subscribersRef.current.filter(
        (subscription) => !Object.is(subscription, fn)
      );
    };
  }
  function notify(data: T) {
    subscribersRef.current.forEach((fn) => fn(data));
  }
  function useSubscribeEffect(fn: (data: T) => void) {
    useEffect(() => subscribe(fn), []);
  }
  return { subscribe, notify, useSubscribeEffect };
}

and have a useRef and useEffect that will call notify on the MomentText component.

Seems quite overkill but not really sure which is worse.

The first approach is easy to understand, but may be a performance hit

The second is a bit more complicated, but the usage is isolated since it's just a context requirement and everything else can be handled by subscriptions within the component.

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

Seems like the idea I had with the context would indeed work, but I had to create a new hook called useClock which is implemented below.

import { useEffect, useRef } from "react";

import { SubscriptionManager, useSubscription } from "../useSubscription";

/**
 * time to next full minute from the date
 * @param date
 * @returns milliseconds to next full minute from date
 */
function timeToNextFullMinute(date: number): number {
  return 60000 - (date % 60000);
}
/**
 * This hook notifies the subscribers with the current date.  This
 * is useful for updating components that show moment in time without
 * a full rerender of the tree.
 *
 * It notifies at the following points:
 * - useEffect
 * - first minute at zero seconds
 * - every minute after at zero seconds
 *
 * However, due to the performance of the device, this may not be acurate.
 *
 * @returns subscription manager
 */
export function useClock(): SubscriptionManager<number> {
  const { subscribe, notify, useSubscribeEffect } = useSubscription<number>();
  const timeoutRef = useRef<ReturnType<typeof setTimeout>>();

  function doNotify() {
    notify(Date.now());
    timeoutRef.current = setTimeout(doNotify, timeToNextFullMinute(Date.now()));
  }
  useEffect(() => {
    doNotify();
    return () => {
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      clearTimeout(timeoutRef.current!);
    };
  }, []);

  return { subscribe, notify, useSubscribeEffect };
}

My context would then provide the useSubscribeEffect specific to the useClock hook which I then use from MomentText which would be:

type MomentTextProps = Omit<TextProps, "children"> & {
  on: Date | number;
};
export function MomentText({ on, ...props }: MomentTextProps): JSX.Element {
  const { useClockSubscribeEffect } = useDevhausUI();
  const { formatRelativeToNow } = useLocalization();
  const [text, setText] = useState(formatRelativeToNow(on));

  useClockSubscribeEffect(() => setText(formatRelativeToNow(on)));

  return <Text {...props}>{text}</Text>;
}

With this approach, the timeout is managed in the useClock() hook and it is part of a context so there's not too many running around.

Source and test available at https://github.com/trajano/react-hooks-tests/tree/master/src/useClock

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda