Getting Started with Recoil and Recoil Hooks: When and How to Use Them

Shuntaro
3 min readJun 26, 2024

--

Recoil is a state management library for React designed to make state sharing between components seamless. It introduces concepts like atoms and selectors, along with hooks for interacting with these states. This blog aims to clarify the usage of Recoil’s get, set, and reset methods and its React hooks.

What is Recoil?

Recoil is a state management library designed for React, providing a way to manage state across components efficiently. It introduces atoms and selectors, which are fundamental units for state management, along with several hooks to interact with them.

Atoms and Selectors

Atom

Atoms are the primary building blocks of Recoil state management. They represent state variables, and when an atom’s value changes, any component that uses that atom re-renders automatically.

Selector

Selectors are derived state, meaning they compute new state based on atoms or other selectors. When the state they depend on changes, selectors recompute their values.

You can manipulate atoms and selectors using get, set, and reset functions:

  • get: Retrieves the current value of an atom or selector.
  • set: Sets a new value for an atom. For selectors, it can set the values of dependent atoms or selectors.
  • reset: Resets an atom’s value to its default state.
import { atom, selector } from “recoil”;

// Define an atom
export const textState = atom({
key: “textState”,
default: “”,
});

// Define a selector
export const charCountState = selector({
key: “charCountState”,
get: ({ get }) => {
const text = get(textState);
return text.length;
},
});

React Hooks in Recoil

Recoil provides several hooks to work with atoms and selectors:

  • useRecoilState: Similar to React’s useState, it returns the current state of an atom and a function to update it.
  • useRecoilValue: Returns only the current value of an atom or selector. Use this when you only need to read the state.
  • useSetRecoilState: Returns a function to update an atom’s state without reading the current value. Useful for updating state without needing to read it first.
  • useResetRecoilState: Returns a function to reset an atom’s state to its default value.

Here’s an example demonstrating these hooks:

import React from "react";
import {
RecoilRoot,
useRecoilState,
useRecoilValue,
useSetRecoilState,
useResetRecoilState,
} from "recoil";
import { textState, charCountState } from "./state";

function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = (event) => {
setText(event.target.value);
};
return (
<div>
<input type="text" value={text} onChange={onChange} />
<p>Text: {text}</p>
</div>
);
}

function CharacterCount() {
const count = useRecoilValue(charCountState);
return <div>Character Count: {count}</div>;
}

function TextInputWithSetOnly() {
const setText = useSetRecoilState(textState);
const onChange = (event) => {
setText(event.target.value);
};
return (
<div>
<input type="text" onChange={onChange} />
<p>Set text directly</p>
</div>
);
}

function ResetText() {
const resetText = useResetRecoilState(textState);
return <button onClick={resetText}>Reset Text</button>;
}

function App() {
return (
<RecoilRoot>
<TextInput />
<CharacterCount />
<TextInputWithSetOnly />
<ResetText />
</RecoilRoot>
);
}

export default App;

Differences and Best Practices

The key takeaway is to understand when to use get, set, and reset versus the hooks. get, set, and reset are primarily used for defining and manipulating state within the atom or selector definition files. In contrast, hooks like useRecoilState and useRecoilValue are designed to be used within React components, making state management straightforward and similar to using other React hooks.

For complex logic, you can create custom hooks where you might directly use get and set methods. Here's an example:

export const useTodo = () => {
const setFromArray = useRecoilCallback(({ set }) => (todoArray) => {
todoArray.forEach((todo) => {
set(stateTodo(todo.id), todo);
});
});

const upsertTodo = useRecoilCallback(({ set }) => (newTodo) => {
set(stateTodo(newTodo.id), newTodo);
});

const removeTodo = useRecoilCallback(({ set, reset }) => (todoId) => {
reset(stateTodo(todoId));
set(stateTodoIds, (prev) => prev.filter((id) => id !== todoId));
});

return {
setFromArray,
upsertTodo,
removeTodo,
};
};

You can find more details in the [recoil-frontend-ddd-sample](https://github.com/susiyaki/recoil-frontend-ddd-sample/blob/master/src/hooks/todo.ts) repository by susiyaki on GitHub.

Conclusion

For simple use cases, utilize get and set within the atom or selector definitions and use hooks in components. For more complex logic, consider creating custom hooks that leverage get and set.

By understanding these distinctions and best practices, you can effectively manage state in your React applications using Recoil.

--

--