docs/basics/comparison.mdx
Jotai was born to solve extra re-render issues in React. An extra re-render is when the render process produces the same UI result, where users won't see any differences.
To tackle this issue with React context (useContext + useState), one would require many contexts and face some issues.
Traditionally, a top-down solution to this is to use a selector function. The use-context-selector library is one example. The issue with this approach is the selector function needs to return referentially equal values to prevent re-renders, and this often requires a memoization technique.
Jotai takes a bottom-up approach with the atomic model, inspired by Recoil. One can build state combining atoms, and optimize renders based on atom dependency. This avoids the need for memoization.
Jotai has two principles.
useState.Jotai's core API is minimalistic and makes it easy to build utilities based upon it.
You can view Jotai as a drop-in replacement to useContext. Except Jotai is aiming for simplicity, minimalistic API and can do much more than useContext & useState.
We can see how we used to share data to children, compared to how we do it with Jotai. But let's use a real-world example where we have multiple Context in our app.
// 1. useState local state
const Component = () => {
const [state, setState] = useState(0)
}
// 2. Lift local state up and share it via context
const StateContext = createContext()
const Parent = ({ children }) => {
return (
<StateContext.Provider value={useState(0)}>
{children}
</StateContext.Provider>
)
}
const Component = () => {
const [state, setState] = useContext(StateContext)
}
// 3. Have multiple states and contexts
const State1Context = createContext()
const State2Context = createContext()
const Parent = ({ children }) => (
<State1Context.Provider value={useState(0)}>
<State2Context.Provider value={useState(0)}>
{children}
</State2Context.Provider>
</State1Context.Provider>
)
const Component1 = () => {
const [state, setState] = useContext(State1Context)
}
const Component2 = () => {
const [state, setState] = useContext(State2Context)
}
Now let's see how Jotai simplify it for us. You can just use atoms instead of multiple Context.
import { Provider, atom, useAtom } from 'jotai'
const atom1 = atom(0)
const atom2 = atom(0)
// Optional: you can use Provider's just like useContext,
// ...but if you only need one,
// ...you can just omit it and Jotai will use a default one (called Provider-less mode).
const Parent = ({ children }) => {
return <Provider>{children}</Provider>
}
const Component1 = () => {
const [state, setState] = useAtom(atom1)
}
const Component2 = () => {
const [state, setState] = useAtom(atom2)
}
Jotai means "state" in Japanese. Zustand means "state" in German.
Jotai is like Recoil. Zustand is like Redux.
To hold states, Both have stores that can exist either at module level or at context level. Jotai is designed to be context first, and module second. Zustand is designed to be module first, and context second.
Jotai state consists of atoms (i.e. bottom-up). Zustand state is one object (i.e. top-down).
The major difference is the state model. Zustand is a single store (although you could create multiple separate stores), while Jotai consists of primitive atoms and allows composing them together. In this sense, it's the matter of programming mental model.
(Disclaimer: the author is not very familiar with Recoil, this may be biased and inaccurate.)