DEV Community

Safal Bhandari
Safal Bhandari

Posted on

Harnessing `atomFamily` and `selectorFamily` in Recoil for Dynamic Async State

When working with React applications, managing dynamic and asynchronous data often becomes complex. Recoil, a state management library for React, offers a powerful duo: atomFamily and selectorFamily, which enable developers to manage parameterized state and perform async queries effortlessly.

In this article, we’ll explore how these concepts work together with a practical example: fetching dynamic todos from an API.


1. Understanding atomFamily

  • An atom in Recoil is a unit of state that components can subscribe to.
  • atomFamily allows you to create parameterized atoms, meaning each atom can hold a separate value depending on the parameter passed (like an id).
  • This is ideal for scenarios where you need to manage multiple similar states (e.g., todos, users, posts) without manually creating separate atoms for each.
export const todosAtomFamily = atomFamily({
  key: "todosAtomFamily",
  default: selectorFamily({
    key: "todosSelectorFamily",
    get: function (id) {
      return async function () {
        const res = await axios(`https://dummyjson.com/todos/${id}`);
        return res.data;
      };
    },
  }),
});
Enter fullscreen mode Exit fullscreen mode

Here:

  • Each todosAtomFamily(id) represents a unique todo.
  • The default is powered by a selectorFamily, which fetches data dynamically from the API.

2. Role of selectorFamily

  • A selector in Recoil derives data from atoms or other selectors.
  • selectorFamily allows selectors to be parameterized, so we can query data based on an input (like id).
  • In this case, the selector asynchronously fetches a todo item from https://dummyjson.com/todos/:id.

This makes the atom dynamic: the first time you access todosAtomFamily(2), it triggers the API call for Todo with ID 2.


3. Integrating into the React App

function App() {
  return (
    <RecoilRoot>
      <Todo id={1} />
      <Todo id={2} />
      <Todo id={2} />
      <Todo id={2} />
      <Todo id={2} />
      <Todo id={2} />
    </RecoilRoot>
  );
}

function Todo({ id }) {
  const todo = useRecoilValue(todosAtomFamily(id));
  return (
    <>
      {todo.todo}
      {todo.completed ? "✅ Completed" : "❌ Not Completed"}
      <br />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • <Todo id={1} /> fetches and displays Todo with ID 1.
  • Since Recoil caches atomFamily values, multiple <Todo id={2} /> components won’t re-fetch from the API; they’ll use the cached data.

4. Why This Matters

Dynamic state: No need to define multiple atoms manually.
Automatic caching: Data for each id is stored and reused.
Asynchronous fetching: Data is loaded seamlessly using selectors.
Scalability: Works well for lists of items like products, users, or messages.


5. Conclusion

By combining atomFamily and selectorFamily, you can elegantly manage dynamic and async state in Recoil. This pattern is especially useful when fetching user-specific or resource-specific data from APIs.

In our todo app, each <Todo /> component only needs an id, and Recoil handles the rest—fetching, caching, and sharing state across components.

This approach not only reduces boilerplate but also ensures performance and scalability in larger React applications.

Top comments (0)