Hi. I hope that you like it
Today Let's learn how to use Jotai in a basic usage and keyway, In a previous article Jotais Introduction basic concepts.
Aclaration: I'm not using providers, contexts or redux for this example. Jotai is state management outside of the render
Atom
We need to declare an atom with an initial value primitive as Strings, Arrays, Booleans, Objects, and Nulls.
In React.js, This atom is placed outside of the render. This is great because we can use this atom in others atoms and read or write the atom. With only importing the variable
If you do not know what is the mean of the atom, I recommend reading the introduction Jotais
import { atom } from 'jotai'
export const NAME_ATOM = atom("Inital Value")
//Strings, Arrays, Booleans, Objects, Nulls.
Ok, But how can I read the value or change the value in the render? Well, We have 3 essential hooks for consuming the atoms.
UseAtom
The useAtom hook returns the atom value and an update function as a tuple, just like React's useState. It takes an atom config created with atom().
It's the typical useState but with more improvements
import { useAtom } from "jotai";
const MyComponent = () => {
const [value, setValue] = useAtom(NAME_ATOM)
return ....
}
export default MyComponent
UseAtomValue
UseAtomValue hook only returns the value of the atom.
import { useAtomValue} from "jotai";
const MyComponent = () => {
const name = useAtomValue(NAME_ATOM);
return ....
}
export default MyComponent
UseSetAtom
Sometimes we need to update the state of the atom. but we do not need to know the value
const MyComponent = () => {
const [, setName] = useAtom(NAME_ATOM)
return ....
}
export default MyComponent
This is wrong because we are rendering the component but we do not use the value. So the useSetAtom avoids rendering unnecessaries
import { useSetAtom } from "jotai";
const MyComponent = () => {
const setName = useSetAtom(NAME_ATOM)
return ....
}
export default MyComponent
If you are interested in how works that hook, I recommend reading the official Jotai documentation
Atom Getter or Reader
The atom receives a primitive value or a function. This function is the first method getter. You can only read atom values and create async fetch data
import { atom } from "jotai";
import { atomWithDefault } from "jotai/utils";
export const FETCHUSERS_ATOM = atomWithDefault(async () => {
const fetching = await fetch("https://jsonplaceholder.typicode.com/users");
const result = await fetching.json();
return result as User[];
});
const ReadfetchAtom = atom((get) => {
return {
users:get(FETCHUSERS_ATOM),
author:get(NAME_ATOM)
}
});
In this case, we are using atomWithDefault because is a function to create a resettable primitive atom. Its default value can be specified with a read function or async function instead of a static initial value.
And atom with a getter function. we return the data of FETCHUSERS_ATOM with the function get
FETCHUSERS_ATOM is a fetching data to JSONPlaceholder and returns a list of users. We can use this atom with the Jotai hooks. but in this case, I'm consuming the data in another atom.
REMEMBER!
When you are working with async atoms. Use the suspense component of react.js recommended by the official documentation Jotai Async
Atom Getter but with Setter and Arguments
With this option, you can declare atoms to set other atoms and read them.
For example, if I have a to-do list, and I need to delete only one, I declare an atom only to set the main atom.
But why do I do not that in the render?
Because when I add more to-do's I'm going to render the component. and that is wrong.
type TodoListProps = {
id: string;
title: string;
};
type DeleteProps = {
id: string;
};
export const TODOLIST_ATOM = atom([] as TodoListProps[]);
///////////////////////////////////////////////////////
const DELETEATOM = atom(null, (get, set, args: DeleteProps) => {
const todos = get(TODOLIST_ATOM);
set(
TODOLIST_ATOM,
todos.filter((item) => item.id !== args.id)
);
});
We have a TodoList with a default array atom. and have a setter delete atom, we call the todo list we can filter the array with the id to delete an item.
Other examples.
const RESET_ATOMS = atom(null, (get, set) => {
set(TODOLIST_ATOM, []);
set(FETCHUSERS_ATOM, []);
set(NAME_ATOM, "Default Name");
set(IMAGE_ATOM, URL_DEFAULT);
});
////// RENDER ////
const setAtoms = useSetAtom(RESET_ATOMS);
REMEMBER!
Your atom only works with the 3 methods.
Read
Read and Write
Write
If your atom is setter other atoms you can't use the value or if your atom is only read you can't set the atom in that atom.
This is a basic example of using atoms. Exist a lot more examples in the official documentation and use cases. I recommend reading the documentation.
If you are interested in the example. I have created an example using Lucy Nxtjs, Jotai and Vite.
Sources:
Jotai
Daishi Kato
If you are interested follow me.