Atom Access Methods
TODO: collapasable, copyable, download, etc
If I use jotai storage, and I have to pass an atom in, where do I get the atom when I'm in a deeply nested sub-component?When using Jotai in a React project, atoms are pieces of state that can be shared across your components. To access an atom in a deeply nested sub-component, you have a few options:
Contextual Access: The most straightforward way to use an atom in a deeply nested component is to import and use it directly. Since Jotai uses React's Context API under the hood, any component in your application can access an atom as long as it is within a provider (in Jotai's case, the provider is often implicit unless you're using advanced features).
Prop Drilling: While not recommended for very deep component trees or highly reusable components, you can pass atoms down through props. This can become cumbersome if the component hierarchy is deep, and generally, it's better to use the atom directly in the components where it's needed.
Custom Hooks: If your component interaction with atoms is complex, you might encapsulate the logic in custom hooks. These hooks can import and manage atoms, handling updates and effects as needed. Sub-components can then use these hooks to interact with the state without worrying about the atom logic.
Higher Order Components (HOCs): This is another method to enhance components with additional capabilities like accessing and managing atoms. However, this pattern is less used in modern React development compared to hooks.
Provider Pattern: If specific subtree needs a different or modified state, you can create a new context (using React's Context API) that provides the necessary atoms or state values down the component tree. This is more advanced and generally used when you have configurable sub-trees within your application.
Here’s a simple example to demonstrate how you might use an atom in a deeply nested component:
import { atom, useAtom } from 'jotai';
import React from 'react';
// Define an atom
const countAtom = atom(0);
// Deeply nested component
const DeepComponent = () => {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
// Example of using the DeepComponent in an application
const App = () => {
return (
<div>
{/* Some other components */}
<DeepComponent />
</div>
);
};
export default App;
In this example, DeepComponent
accesses the countAtom
directly through useAtom
. This is generally the best way to use Jotai atoms as it keeps your component decoupled from its parent components and avoids prop drilling.This example doesn't use useStorage
. This is my qustion, when do I need useStorageThe useStorage
function from Jotai is designed to synchronize an atom's state with a storage mechanism, such as localStorage
or sessionStorage
. This allows the atom's state to persist across page reloads or when navigating between components in your application. The useStorage
hook is particularly useful in scenarios where you want to maintain state consistency even after a browser refresh, or when you want to keep user settings or data without needing to fetch them again from a server.
Here’s how you would typically use useStorage
with Jotai:
Install the Jotai Utils Package: First, ensure you have the
jotai/utils
package installed, asuseStorage
is part of the utilities package.Setup the Atom with Persistence: You would define an atom normally and then wrap it with a persistence function that utilizes
useStorage
.
Here is an example to illustrate this:
import { atom } from 'jotai';
import { useAtom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';
import React from 'react';
// Define an atom with localStorage persistence
const countAtom = atomWithStorage('count', 0);
// Component that uses the atom
const Counter = () => {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
const App = () => {
return <Counter />;
};
export default App;
In this example:
atomWithStorage
is used to create an atom that syncs withlocalStorage
. The first argument is the key forlocalStorage
, and the second is the initial state.- The
Counter
component uses this atom withuseAtom
. Each time the counter is incremented, the state is automatically updated inlocalStorage
. If the user refreshes the page, the count will be initialized fromlocalStorage
instead of resetting to zero.
When to Use useStorage
:
- Persistence: When you need the state to persist across sessions or page reloads.
- Settings: For user settings or preferences that should not reset every time the app is closed or refreshed.
- Drafts: Storing drafts or unsaved changes that should be retrievable if the user leaves the page.
For accessing this atom in deeply nested components, you would simply import the atom definition and use it with useAtom
, just as you would with any other atom. There's no need to pass the atom through props or context since all components using the atom will share the state, backed by the same storage mechanism.
Related Chats
Atom Access Methods 1.000
Provider vs useAtom: when? 0.786
Force Sync Read Atom. 0.652
Jotai with React Query 0.634
Use Effect vs Component Body 0.451
React TypeScript Component: Props & Render 0.387
Memo Once, No Dependencies 0.380
Svelte Click Callback Structure 0.364
Fix TS Error: useAtom 0.362
No need setFoo. 0.356