ReactT2 Dark_1200x303

Learn about the new library introduced by Facebook called Recoil, which aims to solve a few problems such as shared state, derived data and queries, app-wide observation, and many more.

A developer never stops learning, especially in this time when new libraries and concepts are created almost every day. Part of a developer’s job is to always be aware of what’s happening, what’s been released, and to know if there’s something new being talked about in the community.

React is known for being the best and most-used JavaScript UI library now, and there’s a lot of reasons for that. One of the main reasons React is so popular is the community—it’s always creating and releasing something new that can improve the job of React developers.

This year at the React Europe 2020 conference, the React community was introduced to a new state management library created by Facebook called Recoil. Another state management library for React? What are the benefits of using this new library and not something more familiar and robust, with more examples and use cases, such as Redux?

So, in this article, we will learn more about this state management library called Recoil and understand its use cases, the differences from other state management libraries, and how we can start to use it in our projects.

Why Recoil?

Most state management libraries serve simple applications really well—those applications that don’t have many complex features and need the job to be done quickly. In some cases, we might need to use something more complex to solve a specific problem, and that’s when conventional libraries might not help us any further.

There’s nothing wrong with Redux or MobX, the most popular libraries for React applications. These libraries are useful and, in the majority of cases, they’re enough to keep your state data in order and allow your application to scale very well. The only problem with these libraries is that they require a lot of configuration and we need to set up a bunch of things before getting started, especially with Redux.

To work with Redux, for example, there’s a lot of work that needs to be done to set up a simple store before starting to manage your application state. Most of the time we use third-party libraries for things such as memorization, computed selector values, etc. In these specific cases, Redux cannot help us. So there’s a limit to what we can do and achieve with Redux alone.

The team inside Facebook that created Recoil faced some problems while working in internal app development. For most of the features that they needed, a conventional state management library could not help them, or they would waste a lot of time on it. Things like state sync between components, derived state, app-wide observation, etc.

A few points that Recoil has that make this new state management library very powerful:

  • Shared state— Share the same state in different components in the React tree in a way that’s really performant and consistent.
  • Derived data and queries — Compute things based on changing state efficiently in a very robust and bug-free way. Derived data are things that are computed or related to the state in some way.
  • App-wide state observation — Observe changes, time-travel debugging, persistence, logging—observe everything that’s happening in the app from some component.

Here are the two core concepts that we should learn before starting to use Recoil:

Atoms

An atom is a changeable, subscribable unit of the state. Imagine atoms as a local React state, which any component can subscribe to. Atoms are updatable and subscribable, and changing the value of an atom will re-render every component that’s subscribed to that specific atom. All the components that are subscribed to an atom are sharing the same state.

This is how we can create an atom using Recoil:


const loadingState = atom({

key: 'loadingState',

default: false

});

To create an atom we need to provide a key, which should be a unique value. This key is used for persistence, debugging, etc. Also, we need to provide the default value of our atom, it can be anything such as arrays, objects, strings, functions, etc.

For a component to subscribe to an atom, we need to use the useRecoilState hook. It’s a hook similar to the useState from React, but inside this hook, we pass the atom that we want to subscribe to.


import { atom } from 'recoil';

const loadingState = atom({

key: 'loadingState',

default: false

});

const App = () => {

const [loading, setLoading] = useRecoilState(loadingState);

...

}

Sometimes, we just want to return the value of a specific state. This is very possible and simple to do with Recoil. We can return only the value of an atom, without the setter function, using the useRecoilValue hook.


import { atom } from 'recoil';

const loadingState = atom({

key: 'loadingState',

default: false

});

const App = () => {

const loading = useRecoilValue(loadingState);

...

}

Selectors

A selector is a pure function that can receive an atom or a selector as an input. Given an input, the selector returns a modified state every time the upstream atoms or selectors are updated. Selectors can also be subscribed to, and again, when the selector changes, every component that’s subscribed to that specific selector will be re-rendered.

To create a selector, we need to provide a key, which needs to be a unique value and a get function. This get function returns a modified piece of an atom.


import { selector } from 'recoil';

const checkLoadingState = selector({

key: 'loadingState',

get: ({ get } ) => {

const loading = get(loadingState)

return `Loading is ${loading ? "true" : "false}`

});

Recoil has a pretty simple and powerful API, so everyone can get started easily and quickly with this new state management library. Now that we know a little bit about Recoil, let’s build something so we can see how it works in practice.

## Getting Started

Now that we know the basics of Recoil, the best way to understand it is by creating something. Let’s create an example where we can share the state of our logged-in user between components.

First, let’s create a new create-react-app:

create-react-app recoil-example

Now, let’s install Recoil:

yarn add recoil

In order to use Recoil state, we need to wrap our desired components with a root component called RecoilRoot. Now, we’re able to use Recoil state inside the components that are inside RecoilRoot.

In our App component, we’re going to import the RecoilRoot and put all our components inside it:


import { RecoilRoot } from 'recoil';

const App = () => {

return (

<_RecoilRoot_>

...

</_RecoilRoot_>

);

}

Now, before we create our components to show our state, we’re going to create an atom and a selector. Let’s create a file called helpers. Inside this file, we will import the atom and selector functions from Recoil.

import { atom, selector } from "recoil";

Here’s what we want to do, so things will get clear. We want to create an atom where we can get the current logged-in user. We’re going to create an atom called loggedInUserState and, as a default value, we can pass any name we want.


export const loggedInUserState = atom({

key: 'loggedInUserState',

default: {

name: "John"

}

})

Now, we’re going to create our selector. Our selector will just return a message by getting the name of the current logged-in user. We’re going to create a selector called loggedInUserSelector, and this is how it will look:


export const loggedInUserSelector = selector({

key: 'loggedInUserSelector',

get: ({ _get_ }) => {

const user = get(loggedInUserState)

return `Hello ${user.name}, you're logged in!`

}

})

Inside our loggedInUserSelector selector, we’re using the get function to get the current logged-in user passing our loggedInUserState atom and returning a message.

We’re going to create two components: Header and Dashboard. Inside our Header component, we will just show the current logged-in user. Let’s create our Header component, like this:


import React from "react";

const Header = () => {

return (

<header>

<h3>Logged in</h3>

</header>

)

};

export default Header;

Inside our Header component, we’re going to import our loggedInUserState atom and a hook from Recoil. We’re going to use the useRecoilValue since in this Header component we’re just going to show the current logged-in user.

Let’s import our loggedInUserState and constant called loggedInUser and display the name of the current logged-in user inside our h3 element. Inside our useRecoilValue, we’re going to pass our loggedInUserState atom, which means that now this component is subscribed to this atom, so every time this atom changes this component will be re-rendered.


import React from "react";

import { useRecoilValue } from 'recoil';

import { loggedInUserState } from "./helpers";

const Header = () => {

const loggedInUser = useRecoilValue(loggedInUserState);

return (

<header>

<h3>Logged in: {loggedInUser.name}</h3>

</header>

)

};

export default Header;

We now have our Header component working fine. Now, let’s create our Dashboard component. Inside this component we will be able to show and change the name of the current logged-in user.

This is how our Dashboard component will look at first:


import React from "react";

const Dashboard = () => {

return (

<main>

<h3>Hello. You're logged in</h3>

<h3>""</h3>

<input _type_="text" _value_="" _onChange_={() => {}} />

<button >Submit</button>

</main>

)

};

export default Dashboard;

Let’s import some things now. We’re going to import the useState hook from React to get the value of our input, the useRecoilValue and useRecoilState from Recoil, and our loggedInUserState atom and loggedInUserSelector selector.

We’re going to use the useRecoilState to get our current logged in user and a setter function to set a new user. The useRecoilValue will just return the current logged in user.


const [user, setUser] = useState('');

const [loggedInUser, setLoggedInUser] = useRecoilState(loggedInUserState);

const userLoggedIn = useRecoilValue(loggedInUserSelector);

Now, we’re going to create a function called onChange to get the actual value of the input, and a function called loginUser, which we will use to set the new name of the logged-in user.


const [user, setUser] = useState('');

const [loggedInUser, setLoggedInUser] = useRecoilState(loggedInUserState);

const userLoggedIn = useRecoilValue(loggedInUserSelector);

const onChange = ({ target: { _value_ }}: _any_) => {

setUser(_value_);

};

const loginUser = () => {

setLoggedInUser({ name: user })

};

This is how our final Dashboard component should look like:


import React, { useState } from "react";

import { useRecoilState, useRecoilValue } from 'recoil';

import { loggedInUserState, loggedInUserSelector } from "./helpers";

const Dashboard = () => {

const [user, setUser] = useState('');

const [loggedInUser, setLoggedInUser] = useRecoilState(loggedInUserState);

const userLoggedIn = useRecoilValue(loggedInUserSelector);

const onChange = ({ target: { _value_ }}: _any_) => {

setUser(_value_);

};

const loginUser = () => {

setLoggedInUser({ name: user })

};

return (

<main>

<h3>Hello, {loggedInUser.name}. You're logged in</h3>

<h3>{userLoggedIn}</h3>

<input _type_="text" _value_={user} _onChange_={onChange} />

<button _onClick_={loginUser}>Submit</button>

</main>

)

};

export default Dashboard;

We’re now able to change the name of the current logged-in user. Recoil is, in fact, really awesome. In an application that has a lot of contexts, Recoil can do some magic and replace a lot of code with some simple and powerful atoms and selectors.

Should I Use it?

That’s a question that a lot of developers ask themselves every time they see a new library released. First, you need to understand the point that it solves before starting to migrate your whole project to Recoil.

Here are some points that might help you decide if you should use it or not:

Is your application going to need to share state between components, and you don’t want to rely on something like React Context? Recoil might be a good solution for this.

Does your application need to keep sync from the state between components, need persistence between URLs, and observe everything that’s happening in your React tree? Recoil might be a good solution for this.

Conclusion

In this article, we learned more about a new state management library introduced by Facebook called Recoil. Recoil brings the concepts of atoms and selectors. Atoms are pieces of React state that can be subscribed to by any component inside the root component. Selectors are pure functions that can receive atoms and selectors and return derived state.


Leonardo Maldonado
About the Author

Leonardo Maldonado

Leonardo is a Full Stack Developer, working with everything React-related, and loves to write about React and GraphQL to help developers. He also created the 33 JavaScript Concepts.

Related Posts

Comments

Comments are disabled in preview mode.