Recoil - Facebook's own State Management Library
Tags: javascript, react, beginners, webdev
Published: 2020-05-16 19:24:44

---
title: Recoil - Facebook's own State Management Library
published: true
description: Learn how to use atom and selector to manage state using Recoil.
tags: #javascript #react #beginners #webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/vouoo1zjymbdvuhjzjyh.png
series: [Recoil.js Basics]
---

I have used [Redux](https://redux.js.org/) as my state management library extensively in projects. It takes time to set it up but once everything is up, there is no looking back. 

Since it was sufficient for me, I never tried any options till yesterday when [Recoil](https://recoiljs.org/) an experimental state management library by Facebook was launched. 

Going through examples, I realised it's advantages over Redux, like :  

* _Easy to set up and use_
* _Supports asynchronous State Management_
* _State persistence_ ( I'm still not sure how to implement, but I read regarding this in [Source Code](https://github.com/facebookexperimental/Recoil/blob/master/src/recoil_values/Recoil_atom.js) ) 

This got me like : 

![Shut up and take my money meme image](https://dev-to-uploads.s3.amazonaws.com/i/yewr1qb1ipb6a9csog2v.jpg)
 


__*So how Recoil works?*__

It stores data in **Atoms**. React Components can subscribe to these atoms. The subscription can be used to _get_ and _set_ data from Atoms.

__*To get started, we need to understand few Recoil APIs*__

**_1. RecoilRoot_**

* ``<RecoilRoot />`` is used to wrap component, which needs access to Atoms.
* Children of such components can also access Atoms.
* Preferably, we wrap it around the root of application.
* But, multiple roots can be present with each having different state of the same Atom.

**_2. Atom_**

* ``Atom`` is where you can store state, accessible around the application.
* It takes mainly two arguments, Unique key to identify the Atom and a  default value to start with.

**_3. Selectors_**

* ``Selector`` returns a modified state of an Atom. 
* It takes two argument, Unique Key and a ``get`` function that returns a modified state of the selected Atom.

__*Let's create a simple ToDo list app to implement Recoil*__ 

_Create a simple ``create-react-app`` and clean it for a new project._

__*1. Let's wrap our Root Component i.e App Component in ``index.js`` with ``<RecoilRoot/>`` , this will enable Recoil State in app.*__

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {RecoilRoot} from 'recoil';

ReactDOM.render(
  <React.StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </React.StrictMode>,
  document.getElementById("root")
);
```

__*2. Let's create ``Atom`` and subscribe it to enable ToDo state in ``App.js``*__

```javascript
import React from 'react';
import { atom, useRecoilValue } from 'recoil';

const list = atom({
    key: "list",
    default: []
});

function App() {
  const listState = useRecoilValue(list);

  return (
    <div> 
     {
       listState.map(listItem => 
         <p key={listItem.id}>{listItem.value}</p>
       )
     }
    </div>
  );
}

export default App;

```

* Using ``atom()`` we create ``list Atom`` and initialise it with a unique key and a default value.

* Using ``useRecoilValue(list)`` we subscribe to any changes in ``list Atom`` while it returns current value of ``list``.

__*3. Now to modify state of an ``Atom``, there are two ways!*__

1. Using ``useRecoilState(list)`` which returns an array just like ``useState()`` React hook. This array consists of ``list Atom`` value and a function which can modify ``list Atom`` state.


2. Using ``useSetRecoilState(list)`` which returns a function which can modify ``list Atom`` state.

We will go with the ``useSetRecoilState(list)`` for this one.

```javascript
import React, { useState } from 'react';
import { atom, useRecoilValue, useSetRecoilState } from 'recoil';
import { v4 as uuid4 } from 'uuid';

const list = atom({
    key: "list",
    default: []
});

function App() {
  const [inputValue, updateInputValue] = useState("");
  const listState = useRecoilValue(list);
  const updateList = useSetRecoilState(list);

  const changeValue = event => {
      const { value } = event.target;
      updateInputValue(value);
  }

  const addValue = () => {
     setInput("");
     updateList((oldList) => [
         ...oldList,
         {
           id: uuid4(),
           value: inputValue,
         },
     ]);
  }
  
  return (
    <div> 
        <div>
            <p>Enter item :</p>
            <input type="text" value={inputValue} onChange={e => changeValue(e)}/>
            <button className="addInputButton" onClick={() => addValue()}>Add</button>
         </div>

         {
             listState.map(listItem => 
                 <p key={listItem.id}>{listItem.value}</p>
              )
         }
    </div>
  );
}

export default App;


```
* The function returned by ``useSetRecoilState(list)`` takes a callback function as an argument. 

* The callback function returns a value which is set to the ``list Atom``. 

* The first argument in callback function also holds the current state of ``list Atom``, here, we can use it to append latest item in existing ToDo list.

__*4. Let's add ``Selector`` for our ToDo list!*__

```javascript
import React, { useState } from 'react';
import { atom, useRecoilValue, useSetRecoilState, selector } from 'recoil';
import { v4 as uuid4 } from 'uuid';

const list = atom({
    key: "list",
    default: []
});

const filterListValue = atom({
    key: "filterListValue",
    default: "" 
});

const filterList = selector({
    key: "filterList",
    get: ({get}) => {
        const listState = get(list);
        const filterListValueState = get(filterListValue);
        
        if (filterListValueState.length) {
          return listState.filter((item) =>
            item.value.includes(filterListValueState) && item
          );
        }
        return list;
    }
})

function App() {
  const [inputValue, updateInputValue] = useState("");
  const listState = useRecoilValue(list);
  const updateList = useSetRecoilState(list);

  const changeValue = event => {
      const { value } = event.target;
      updateInputValue(value);
  }

  const addValue = () => {
     setInput("");
     updateList((oldList) => [
         ...oldList,
         {
           id: uuid4(),
           value: inputValue,
         },
     ]);
  }
  
  return (
    <div> 
        <div>
            <p>Enter item :</p>
            <input type="text" value={inputValue} onChange={e => changeValue(e)}/>
            <button className="addInputButton" onClick={() => addValue()}>Add</button>
         </div>

         {
             listState.map(listItem => 
                 <p key={listItem.id}>{listItem.value}</p>
              )
         }
    </div>
  );
}

export default App;


```

* Here we add one more ``Atom`` named ``filterListValue Atom`` which holds the filter query used by ``filterList Selector`` to filter ``list Atom``.

* ``Selector`` here filters list which contains query from ``filterListValue Atom``.

* When ``filterListValue Atom`` value is empty, ``filterList Selector`` returns whole ``list Atom``.

* Function that is assigned to ``Selector``'s get parameter is passed with Object as an argument. The ``get`` property of object is used to retrieve value from ``list Atom`` and ``filterListValue Atom``.

__*5. Once ``Selector`` is added let's add functionality for filter*__

```javascript
import React, { useState } from 'react';
import { atom, useRecoilValue, useSetRecoilState, selector } from 'recoil';
import { v4 as uuid4 } from 'uuid';

const list = atom({
    key: "list",
    default: []
});

const filterListValue = atom({
    key: "filterListValue",
    default: "" 
});

const filterList = selector({
    key: "filterList",
    get: ({get}) => {
        const listState = get(list);
        const filterListValueState = get(filterListValue);
        
        if (filterListValueState.length) {
          return listState.filter((item) =>
            item.value.includes(filterListValueState) && item
          );
        }
        return list;
    }
})

function App() {
  const [inputValue, updateInputValue] = useState("");
  
  const listState = useRecoilValue(list);
  const updateList = useSetRecoilState(list);

  const [filterListState,filterList] = useRecoilState(filterListValue);

  const changeValue = event => {
      const { value } = event.target;
      updateInputValue(value);
  }

  const addValue = () => {
     setInput("");
     updateList((oldList) => [
         ...oldList,
         {
           id: uuid4(),
           value: inputValue,
         },
     ]);
  }

  const filter = event => {
      const { value } = event.target;
      filterList(value);
  }

  const clearFilter = () => filterList("");

  
  return (
    <div> 
        <div>
            <p>Enter item :</p>
            <input type="text" value={inputValue} onChange={e => changeValue(e)}/>
            <button className="addInputButton" onClick={() => addValue()}>Add</button>
         </div>

         <div>
             <p>Filter : </p>
             <input
                type="text"
                value={filterListState}
                onChange={(e) => filter(e)}
             />

             <button onClick={() => clearFilter()}>
                Clear
             </button>
         </div>

         {
             listState.map(listItem => 
                 <p key={listItem.id}>{listItem.value}</p>
              )
         }
    </div>
  );
}

export default App;


```

* Would this work? __*No*__. Why? Because we have not subscribed to ``Selector`` yet, so it might filter ToDo list but won't reflect over the component.

* So we make a small change in our code shown below 

```diff
- const listState = useRecoilValue(list);
+ const listState = useRecoilValue(filterList); 
```

This would complete the little ToDo Application with Add and Filter functionality. If you want to see a more structured approach, you can checkout GitHub repository below.

{% github shubhaemk/recoil-example no-readme%} 

_Let me know your opinion on Recoil. In next [post](https://dev.to/shubhamk/recoil-the-asynchronous-way-to-manage-state-part-1-18kk) I have explained asynchronous side of Recoil._ __*Cheers!*__