Data-Aware Components

Normalmente, al crear un app de React, un componente necesita un dato del API, ej. el usuario logueado, entonces hacés el fetch, manejás el estado de cargando y de un posible error, y listo, todo funciona y seguís armando tu app.

Pero muchas veces esta data la terminas necesitando en más componentes, lo que te da 2 opciones:

  1. Duplicas el código, o lo extraes a un hook, y haces el fetch cada vez que lo necesites
  2. Movés la lógica a un componente padre de todos los que lo necesiten y haces un fetch.

El primer caso es super ineficiente y nadie lo hace de verdad en producción, debido a la gran cantidad de requests duplicados que terminás haciendo.

El segundo es lo más común, y normalmente combinado con algo como Context o Redux para evitar pasar como props la data a cada componente que lo necesites, lo guardas en un lugar global y todos lo leen directo desde ahí con un solo useCurrentUser hook.

Esto sirve, y podés seguir con esta estrategia un montón de tiempo, pero no por eso es lo mejor. En cambio podémos mejorar esto un montón creando data-aware components, veamos de que va.

Un data-aware component es un componente que hace algo similar al primer caso, es capaz de hacer el fetch, manejar estados de carga y error y renderizarse, de forma totalmente independiente. Si ningún otro componente usa la misma data hace el fetch y listo, ningún otro se entera.

Pero, si más de un componente usa la misma data, el request se hace una sola vez y se comparte la cacha del API entre todos los que lo necesites 🤯

Esto es genial, porque los componentes pueden de verdad ser independientes, es posible mover el componente a otra app y funciona.

Veamos un ejemplo:

function CurrentUserAvatar() {
  const { data, error } = useCurrentUser()

  if (error) return <ErrorAvatar />
  if (!data) return <LoadingAvatar />
  return <Avatar src={data.avatarUrl} src={data.fullName} />
}

Ese componente, lo podemos renderizar N veces y solo se va a hacer el fetch del usuario actual una vez.

Para esto, podemos usar dos libs, SWR (mi favorita) o React Query (igual de buena), estas libs lo que tienen de especial es que tienen una cache donde guardan la data y evitan los requests duplicados automáticamente, en un rango de tiempo configurable.

SWR usa 2 segundos, así que todos los renders que usen la misma key de cache van a hacer un solo fetch, cualquier render luego de estos 2 segundos inicia un nuevo fetch, el cual actualiza la cache y con esto, todos los componentes que usen la misma key.

Esto último es muy importante, como todos comparten la misma cache cualquier componente que haga un fetch y actualice la data actualiza toda la app al mismo tiempo, así toda la app va a ser eventualmente consistente.