React Native

Recoil 's atomFamily: simplifying state management in your React applications

If you're working with complex and interconnected state in your React application, Recoil's ++code>atomFamily++/code> function may be a valuable tool in your state management arsenal. ++code>atomFamily++/code> allows you to create a family of atoms that share the same properties but have unique keys, making it easy to manage multiple instances of the same state.

In this article, we will discuss the benefits and best practices of using ++code>atomFamily++/code> in React. We will also provide an example implementation. By the end, you will be prepared to use ++code>atomFamily++/code> effectively in your own projects.

So let's get started!

Understanding “atomFamily” implementation and use case

What is an atomFamily?

First, an ++code>atom++/code> is a piece of state such as a ++code>useState()++/code> in React. But an atom is global; it is defined outside of react (regardless of whether the components that use the atom are mounted or not). It is define like this :

An ++code>atomFamily++/code> is a group of related ++code>atom++/code> that share the same structure and behavior. In React, it would be like if useState depended on a parameter : ++code>useState(id)()++/code>.

What does the implementation of an atomFamily look like?

In this article, we will use Recoil's AtomFamily feature to implement a render-proof todo list example. The implementation is very similar in Jotai, another state management library.

What you need to understand:

  • Typing of the ++code>atomFamily++/code> is ++code>atomFamily<TypeOfYourAtom, TypeOfTheId>++/code> (In our case Todo is ++code>type Todo = { text: string; isDone: boolean; }++/code>)
  • ++code>key++/code> is a unique string to identify your store
  • ++code>default++/code> is the default value of the member of your family. All values exist! So calling ++code>useRecoilState(todoAtomFamily(anyId))++/code> will work and return either the default or the value if it has been defined !
  • This is also why we need to keep track of which ids are being used in a basic array. You can’t access the lists of used atoms from Recoil.

Then we define functions to update our store. These functions need to update both the ++code>todoAtomFamily++/code> and the ++code>todoUsedIdsAtom++/code>.

What you need to understand:

  • The syntax of ++code>useRecoilCallback++/code> is similar to a ++code>useCallback++/code> but it exposes some util functions to update the store (reset, set, …) : ++code>useRecoilCallback(({set, reset, ...}) => (callbackParams)=> { /* The core of the function */}, [depArray])++/code>

Our store is now ready to be used:

Tadaa !

Now if you want to make it interactive, you can access the state of the atoms with ++code>useRecoilState(todoAtomFamily(id))++/code> which works exactly like a ++code>useState++/code>. If you want to use only the value you can use ++code>useRecoilValue++/code> and if you want only the setter you can use ++code>useSetRecoilState++/code> (This is an example for todos but you can have any list of interactive elements).

Evaluating performance benefits for your app

If we display the re-renders we can see that toggling a todo does not cause a re-render in the other todos. One of the major benefits of using AtomFamily is its ability to improve performance by minimizing unnecessary re-renders. Since each item in the family depends only on its own atom, it won't re-render when others change. This is particularly important in complex applications, such as drawing apps, where rendering can be expensive and time-consuming. In these cases, using AtomFamily can significantly improve performance and user experience.

image
image

TIP
You can show the renders on the web by clicking "Highlight updates when components render" in the React DevTools browser extension. (chrome or firefox)

But do you need an atomFamily?

So, you only need an atomFamily if you have a list of interactive item and you care about performance.

Comparison with Zustand

Zustand is a super popular state management library. It has slowly become a standard for most React / React Native projects. Here’s the doc to better understand Zustand. Let’s see how we would implement a similar feature with the same performance.

The store definition is much simpler than Recoil:

  • In Zustand, we define the function to edit the store (addTodo and toggleIsDone) inside the store

The page implementation is similar to that in Recoil.

The biggest difference is in the implementation of the list and item:

As you can see, achieving a render-proof implementation can be more challenging compared to Recoil's ++code>atomFamily++/code>. Zustand requires the use of memoized selectors and an ++code>equals++/code> function (also memoized) to determined if the selected states are equal or not, which adds complexity to the implementation.

So, while it is possible to achieve similar render performance with other state management libraries like Zustand, Recoil's AtomFamily provides a more intuitive approach that can lead to better performance in the long run. With AtomFamily, developers are encouraged to break down complex states into smaller, independent atoms, which can lead to more efficient rendering and easier debugging. Additionally, Recoil has some built-in dev tools to make it easy to monitor and optimize performance.

Conclusion

In conclusion, ++code>atomFamily++/code> is a powerful feature in Recoil that allows you to manage a group of related atoms with shared structure and behavior. It is particularly useful when dealing with a list of interactive items and performance optimization is crucial.

The main advantage of using ++code>atomFamily++/code> in Recoil is its ability to minimize unnecessary re-renders, improving performance in complex applications. This is achieved by creating independent atoms for each item in the family, which only re-render when their respective atom changes. Additionally, Recoil provides a more streamlined approach to breaking down complex states and offers built-in dev tools for performance monitoring and optimization.

While Zustand offers a simpler store definition and similar performance optimization capabilities, Recoil's ++code>atomFamily++/code> presents a more intuitive approach to state management, especially for developers who care about performance and wish to work with lists of interactive items. Ultimately, both Recoil and Zustand have their merits, and the choice between them will depend on your specific requirements and personal preferences.

Développeur mobile ?

Rejoins nos équipes