Top 3 Pro Tips for Harnessing Jotai: Supercharge Your State Management in React

Matthew Hill
4 min readJul 11, 2023

--

Introduction:
Jotai is a powerful state management library for React that provides a simple and scalable approach to managing state in your applications. With its focus on atomic updates and declarative syntax, Jotai offers a refreshing alternative to traditional state management solutions. In this article, we will explore the top three pro tips for utilizing Jotai effectively, along with code examples that showcase its capabilities and help you unlock the full potential of this state management library.

  1. Embrace Atom Families for Dynamic State Management:
    Atom families in Jotai allow you to create a group of atoms that share the same behavior and state structure while varying based on dynamic input. This feature is particularly useful when dealing with lists or collections of data. Let’s dive into an example:
import { atom, atomFamily, useAtom } from "jotai";

// Atom Family
const todoAtomFamily = atomFamily((id) => atom(false));

// Component
const TodoItem = ({ id }) => {
const [completed, setCompleted] = useAtom(todoAtomFamily(id));
const handleToggle = () => {
setCompleted((prev) => !prev);
};

return (
<div>
<input type="checkbox" checked={completed} onChange={handleToggle} />
<span>{id}</span>
</div>
);
};

const TodoList = ({ todos }) => {
return (
<div>
{todos.map((todo) => (
<TodoItem key={todo.id} id={todo.id} />
))}
</div>
);
};

// Usage
const todos = [
{ id: 1, text: "Learn Jotai" },
{ id: 2, text: "Build an app" },
{ id: 3, text: "Deploy to production" },
];

const App = () => {
return <TodoList todos={todos} />;
};

In the example above, we define an atom family called todoAtomFamily that takes an id as input and returns an atom representing the completion state of a todo item. Each TodoItem component receives a unique id prop and uses the useAtom hook with todoAtomFamily(id) to manage the completion state of that specific item. This allows us to dynamically handle the state of each individual todo item using a single atom family.

2. Leverage Derived Atoms for Computed Values:
Derived atoms in Jotai enable you to create atoms whose value is derived from other atoms, providing a convenient way to compute values based on existing state. This feature is especially useful when you need to derive derived state or perform complex computations. Let’s explore an example:

import { atom, useAtom, atomFamily, derived } from "jotai";

const todosAtom = atom([
{ id: 1, text: "Learn Jotai", completed: true },
{ id: 2, text: "Build an app", completed: false },
{ id: 3, text: "Deploy to production", completed: false },
]);

const completedCountAtom = derived(todosAtom, (todos) =>
todos.reduce((count, todo) => (todo.completed ? count + 1 : count), 0)
);

const TodoList = () => {
const [todos] = useAtom(todosAtom);
const [completedCount] = useAtom(completedCountAtom);

return (
<div>
<h2>Todo List</h2>

{todos.map((todo) => (
<div key={todo.id}>
<span>{todo.text}</span>
<input type="checkbox" checked={todo.completed} />
</div>
))}

<p>Completed: {completedCount}</p>
</div>
);
};

const App = () => {
return <TodoList />;
};

In this example, we have an todosAtom representing an array of todos. We create a derived atom called completedCountAtom that computes the number of completed todos based on the todos array. The derived function takes the todosAtom and a function that calculates the derived value. The completedCount is then accessed and rendered in the TodoList component. Whenever the todos array changes, the derived atom will be automatically updated, ensuring that the computed value remains in sync.

3. Optimize Performance with Atom Cloning:
Jotai provides an efficient mechanism for atom cloning, which helps prevent unnecessary re-renders of components that depend on specific atoms. By cloning atoms, you can isolate the scope of updates to the cloned atom and its descendants, minimizing unnecessary renders in unrelated parts of the application. Let’s explore an example:


import { atom, useAtom, cloneAtom } from “jotai”;

const countAtom = atom(0);

const Counter = () => {
const [count, setCount] = useAtom(countAtom);

const handleIncrement = () => {
setCount((prevCount) => prevCount + 1);
};

const handleReset = () => {
setCount(0);
};

return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleReset}>Reset</button>
</div>
);
};

const ClonedCounter = () => {
const clonedCountAtom = cloneAtom(countAtom);
const [count, setCount] = useAtom(clonedCountAtom);

const handleDecrement = () => {
setCount((prevCount) => prevCount - 1);
};

return (
<div>
<p>Cloned Count: {count}</p>
<button onClick={handleDecrement}>Decrement</button>
</div>
);
};

const App = () => {
return (
<div>
<Counter />
<ClonedCounter />
</div>
);
};

In this example, we have a countAtom representing a counter’s value. The Counter component uses the original countAtom, while the ClonedCounter component clones the countAtom using cloneAtom. By cloning the atom, the ClonedCounter component is isolated from unnecessary re-renders caused by updates to the original countAtom. This optimization ensures that only the relevant components are re-rendered when their respective atoms change.

Conclusion:
Jotai provides powerful tools for state management in React applications, and by mastering advanced techniques such as embracing atom families, leveraging derived atoms for computed values, and optimizing performance with atom cloning, you can take your state management to new heights. These pro tips will help you write clean, scalable, and efficient code, enabling you to build complex applications with ease. Embrace Jotai’s declarative approach and explore its rich feature set to unlock the full potential of state management in your React projects. Happy coding!

--

--