Technology

State management with Recoils.js

State management with Recoils.js

The word “Recoil” describes an unexpected outcome of an action or a reactive effect to an action. The recoil of a gun is used to name the backward pull that occurs firing a bullet which is a reactive effect. In addition, it is used to address the sudden reactions of a person as ‘He recoiled in fear’.

In RecoilJs, the unexpected behavior (recoil) of a react app is controlled. Here it is referred to the unwanted re-renders of the components which consumes a lot of processing power and make the app less smooth in functioning. On the other hand, the two main core concepts, shared state and derived state can be used to manage the state very easily without making the code more complicated.

Atom

In recoilJS, state is addressed by dividing it to. An atom is one of those pieces. It will be subscribed by components and as well as selectors and whenever an atom changes its state that component will re-render and the selectors will re-run.

Selector

Selector acts similar to an atom as the return value is the same type as an atom (RecoilState). But that value is derived using an atom. When that atom changes its state the selector also returns its updated derived recoil state.

AtomFamily

AtomFamily is used to get an atom in dynamic instances. This is very helpful to make the app more scalable. Unlike atoms or selectors, atomFamily holds a function to return an atom.

State Management in Recoil

Each component in an app has a State which will hold the data that need to be displayed or control the user interactions.

Sometimes these states may have common components (shared state) or some components use a derived state of another component (derived state). Recoil is designed to easily handle these 2 instances with atoms and selectors. Atoms will hold the state while the selectors will create the derived state from an atom. Selector is also a type of atom; it returns the derived state of an atom.

Redux and Context state management libraries also support these instances. But when a piece of a state of a component is changed in these systems, all the subcomponents of the component are re rendered regardless of the dependency of that piece of state to the subcomponent.

In Recoil, that action of re-rendering all the components is hindered as it considers the state as a set of small states and the sub components or components are made to subscribe to a small state (atom). In this way the component or the sub component re-renders only when that piece of state is changed. RecoilJS is very useful in such complex applications where the UI has many components that do not necessarily need re-rendering as another component is rendered.

In addition, A state aggregator can be used to accumulate all the states of the components to one place creating a store-like architecture as in Redux. Creating a store in recoil will grant all the privileges you have when you use redux but more enhanced in performance. Performance optimization is mostly a tradeoff with memory optimization. A complex application may hold 1000s of atoms occupying a lot of memory. Recoil uses a ‘Hash array mapped trie’ data structure for holding atoms. This has paved the way to access the atoms more faster with less memory usage.

Atoms in recoil can be defined in the components as read-only, write only and read and write, giving more security and structure to the application.

Take an app that is used for Shop to display their goods. In the home page there will be 3 main components NavBar, Body and the Footer. And inside the Body items of the shop and the cart is displayed. Whenever a user wants an item he clicks on it and it gets highlighted and then the cart is updated with total price.

Recoil.js state tree

Each shop item will have an atom for its state. then an item is highlighted only that item is re rendered as that item has an atom.

In other state management libraries one click on a shop item will render all the elements of the body including navbar and the footer of the page. Therefore this solution is not scalable. The more the products are, the time taken to render is high. Therefore using recoil as follows can maximize the performance.

The HomePage is created to show the shop items and the cart in the body of it. At the start of the mounting the shop item data is loaded with asynchronous useEffect.

Recoil.js state management

In the ShopItem component when the app loads a shop item it creates an atom to represent that shop item. This way only the required item is re-rendered. atomFamily is used to return an atom for that item according to the id of the item.

Recoil.js state management

ShopItemAtom atom is used to contain all the shop items array retrieved from an API call.

Recoil.js state management

The total price that is going to be shown in the cart is held in another atom

Recoil.js state management

Another atom to hold the selected items is also created

Recoil.js state management

A write-only version of selectedItemsAtom is created and passed as a prop to the ShopCard component to keep track of the selected items. By using useSetRecoilState a write-only instance of an atom can be obtained. Not only that the component will not be subscribed to the atom. Therefore, a re-render will not be triggered when setting up the state.

Recoil.js state management

When a user clicks an item, only that clicked item should be highlighted. Therefore the state should be updated without re-rendering other components.

Components that need to be re-rendered are the cart and the clicked shop item.

Recoil.js state management

Since the state of an atom changes that particular item re-renders while other items are kept the same. However the cart needs to be re-rendered. That will be done in the cart component.

Recoil.js state management

In this component it uses useRecoilValue to subscribe to the totalAtom. As the ShopCard atom changes the state of the total atom cart component is re-rendered as a whole component. For this to work correctly, it is required to have the cart component as a separate component as it is subscribed to the totalAtom and that will re-render the whole component.

If the cart was displayed in the home component the whole component will re-render with the change of the state of totalAtom.

Conclusion

Overall, Recoil is one of the best libraries to easily handle the state management of a complex app. If the app has a high scalability need in performance you may need to start from Recoil otherwise the previous state managements are better to be used.

Recoil is a library whereas you can use it to perform many interactions with the state while having control with the react rendering process.

Thank you for reading, Hope you will have more recoil control on your apps in future

For more insights on Recoil check the following link

recoiljs.org

Find more @ zegates.com

Malitha Liyanage

Malitha Liyanage

Software Engineer