Recoil is a relatively new state management library specifically built for React applications by Facebook. It is designed to be simple yet powerful, allowing you to manage both local and global state efficiently while solving problems like prop drilling and complex data flows.
Recoil is a state management library for React that provides a novel way to share state across components while keeping the data flow manageable and predictable. Recoil enables fine-grained state management and comes with a few unique features:
Recoil offers several advantages over other state management libraries:
Before using Recoil in your React application, you need to install the Recoil library.
Run the following command in your project directory to install Recoil:
npm install recoil
Once installed, you need to wrap your application with the RecoilRoot component. This component acts as the context provider for your Recoil state.
import React from 'react';
import ReactDOM from 'react-dom';
import { RecoilRoot } from 'recoil';
import App from './App';
ReactDOM.render(
,
document.getElementById('root')
);
RecoilRoot
: This component wraps the entire application to give access to the Recoil state across all components. It’s similar to how you would wrap your app with Redux’s Provider
or React Context.Atoms are the smallest units of state in Recoil. They are used to store pieces of state that can be shared between multiple components.
Let’s start by creating a simple atom to store a piece of state, such as a counter value.
import { atom } from 'recoil';
export const counterState = atom({
key: 'counterState', // A unique key to identify this atom
default: 0, // The default value for this atom
});
atom
: This function creates a new Recoil atom.key
: Each atom requires a unique key that identifies it in the Recoil state tree.default
: The initial value of the atom, in this case, it’s set to 0
.Now that we’ve created the counterState
atom, let’s use it in a component to display and update the counter value.
import React from 'react';
import { useRecoilState } from 'recoil';
import { counterState } from './atoms';
const Counter = () => {
const [count, setCount] = useRecoilState(counterState);
return (
Counter: {count}
);
};
export default Counter;
useRecoilState
: This hook is used to read and update the value of an atom. It works similarly to React’s useState
, but it allows the state to be shared across multiple components.count
: The current value of the counterState
atom.setCount
: A setter function to update the value of the counterState
atom.When you run the app, you’ll see a counter displayed with “Increment” and “Decrement” buttons. Clicking these buttons will update the counter, and the UI will re-render to reflect the updated value.
Selectors in Recoil allow you to create derived state. They can depend on atoms or other selectors and are recalculated whenever their dependencies change.
Let’s create a selector that doubles the value of our counter.
import { selector } from 'recoil';
import { counterState } from './atoms';
export const doubledCounterState = selector({
key: 'doubledCounterState', // Unique key for this selector
get: ({ get }) => {
const count = get(counterState); // Get the current value of counterState
return count * 2;
},
});
selector
: This function creates a new selector.get
: The get
function is used to read the value of other atoms or selectors.counterState
: We’re using the counterState
atom and multiplying its value by 2.Let’s display the doubled value of the counter in our component.
import React from 'react';
import { useRecoilValue } from 'recoil';
import { doubledCounterState } from './selectors';
const DoubledCounter = () => {
const doubledCount = useRecoilValue(doubledCounterState);
return (
Doubled Counter: {doubledCount}
);
};
export default DoubledCounter;
useRecoilValue
: This hook is used to read the value of an atom or selector without subscribing to changes. In this case, we use it to get the doubledCounterState
value.The component will display the doubled value of the counter. If the original counter is 2
, this component will show 4
. When the counter value is updated, the doubled value will automatically be recalculated and updated in the UI.
Recoil selectors can also be asynchronous, allowing you to handle API requests or perform other asynchronous tasks.
Let’s create a selector that fetches data from an API (for example, user data from a public API).
import { selector } from 'recoil';
export const userDataState = selector({
key: 'userDataState',
get: async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
const data = await response.json();
return data;
},
});
get
: The get
function in a selector can return a promise, making it asynchronous.fetch
: We’re fetching data from a public API (JSONPlaceholder) to get information about a user.Now, let’s use this asynchronous selector to display user data in a component.
import React from 'react';
import { useRecoilValue } from 'recoil';
import { userDataState } from './selectors';
const User = () => {
const userData = useRecoilValue(userDataState);
return (
User Data
Name: {userData.name}
Email: {userData.email}
Phone: {userData.phone}
);
};
export default User;
useRecoilValue
: We use this hook to read the value of the userDataState
selector, which triggers the API request and renders the user data once it is available.The component will display user information fetched from the API, such as the user’s name, email, and phone number.
In many cases, you will need to manage complex state such as arrays or objects. Recoil atoms can handle these scenarios efficiently.
Let’s create a simple todo list application where we store the todos in a Recoil atom.
import { atom } from 'recoil';
export const todoListState = atom({
key: 'todoListState',
default: [], // Default value is an empty array
});
Now let’s create a component to add new todos and display the list of todos.
import React, { useState } from 'react';
import { useRecoilState } from 'recoil';
import { todoListState } from './atoms';
const TodoList = () => {
const [todos, setTodos] = useRecoilState(todoListState);
const [newTodo, setNewTodo] = useState('');
const addTodo = () => {
setTodos([...todos, newTodo]);
setNewTodo('');
};
return (
Todo List
setNewTodo(e.target.value)}
placeholder="Enter a new todo"
/>
{todos.map((todo, index) => (
- {todo}
))}
);
};
export default TodoList;
useRecoilState
: We use this hook to manage the todoListState
atom, which stores the array of todos.addTodo
: This function adds a new todo to the list by updating the atom.You can add todos using the input field, and the list will display all added todos. The state of the todo list is stored in the todoListState
atom, and it’s shared across all components that access this atom.
Recoil is designed to work seamlessly with React Suspense, allowing you to handle asynchronous data fetching more elegantly. When an asynchronous selector is loading, Recoil can trigger the Suspense boundary and show a fallback UI until the data is ready.
Let’s wrap our asynchronous User
component in a Suspense boundary to handle the loading state.
import React, { Suspense } from 'react';
import User from './User';
const App = () => {
return (
Loading...
Suspense
: We wrap the User
component with Suspense and provide a fallback UI (e.g., “Loading…”) that will be displayed while the data is being fetched.When you load the app, you’ll see the fallback UI (“Loading…”) until the user data is fetched, at which point the actual data will be displayed.
Recoil provides utilities to reset the state of atoms. This can be useful when you want to clear or reset state back to its default value.
Let’s modify our todo list example to add a button that resets the todo list.
import React from 'react';
import { useRecoilState, useResetRecoilState } from 'recoil';
import { todoListState } from './atoms';
const TodoList = () => {
const [todos, setTodos] = useRecoilState(todoListState);
const resetTodos = useResetRecoilState(todoListState);
return (
Todo List
{todos.map((todo, index) => (
- {todo}
))}
);
};
export default TodoList;
useResetRecoilState
: This hook provides a function to reset the value of an atom back to its default value.Clicking the “Reset Todos” button will clear the todo list and reset it to an empty array.
Recoil is a powerful and flexible state management library for React applications. It provides a minimalistic and declarative way to manage both local and global state in React. With features like atoms, selectors, and built-in support for async state, Recoil makes it easy to handle complex state management scenarios, while keeping your code clean and efficient. Happy Coding!❤️