Primitive and flexible state management for React applications
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
React hooks and components for integrating Jotai atoms with React applications. These provide the primary interface for using atoms in React components.
Primary hook for reading and writing atom values in React components.
/**
* Hook for reading and writing writable atoms
* @param atom - The writable atom to use
* @param options - Optional configuration
* @returns Tuple of [value, setter] similar to useState
*/
function useAtom<Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
options?: Options
): [Awaited<Value>, SetAtom<Args, Result>];
/**
* Hook for reading and writing primitive atoms
* @param atom - The primitive atom to use
* @param options - Optional configuration
* @returns Tuple of [value, setter] with standard setState interface
*/
function useAtom<Value>(
atom: PrimitiveAtom<Value>,
options?: Options
): [Awaited<Value>, SetAtom<[SetStateAction<Value>], void>];
/**
* Hook for read-only atoms (returns never for setter)
* @param atom - The read-only atom to use
* @param options - Optional configuration
* @returns Tuple of [value, never]
*/
function useAtom<Value>(
atom: Atom<Value>,
options?: Options
): [Awaited<Value>, never];Usage Examples:
import { atom, useAtom } from "jotai";
const countAtom = atom(0);
const textAtom = atom("hello");
function MyComponent() {
const [count, setCount] = useAtom(countAtom);
const [text, setText] = useAtom(textAtom);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
<input
value={text}
onChange={(e) => setText(e.target.value)}
/>
</div>
);
}Hook for reading atom values without the ability to write.
/**
* Hook for reading atom values without write capability
* @param atom - The atom to read from
* @param options - Optional configuration
* @returns The current value of the atom
*/
function useAtomValue<Value>(
atom: Atom<Value>,
options?: Options
): Awaited<Value>;Usage Examples:
import { atom, useAtomValue } from "jotai";
const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);
function DisplayComponent() {
const count = useAtomValue(countAtom);
const doubleCount = useAtomValue(doubleCountAtom);
return (
<div>
<p>Count: {count}</p>
<p>Double: {doubleCount}</p>
</div>
);
}Hook for getting a setter function for writable atoms.
/**
* Hook for getting a setter function for writable atoms
* @param atom - The writable atom to get setter for
* @param options - Optional configuration
* @returns Setter function for the atom
*/
function useSetAtom<Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
options?: Options
): SetAtom<Args, Result>;
/**
* Hook for getting a setter function for primitive atoms
* @param atom - The primitive atom to get setter for
* @param options - Optional configuration
* @returns Standard setState-style setter function
*/
function useSetAtom<Value>(
atom: PrimitiveAtom<Value>,
options?: Options
): SetAtom<[SetStateAction<Value>], void>;Usage Examples:
import { atom, useSetAtom, useAtomValue } from "jotai";
const countAtom = atom(0);
const incrementAtom = atom(null, (get, set, amount: number) => {
set(countAtom, get(countAtom) + amount);
});
function Controls() {
const setCount = useSetAtom(countAtom);
const increment = useSetAtom(incrementAtom);
return (
<div>
<button onClick={() => setCount(0)}>Reset</button>
<button onClick={() => setCount((prev) => prev + 1)}>+1</button>
<button onClick={() => increment(5)}>+5</button>
</div>
);
}
function Display() {
const count = useAtomValue(countAtom);
return <p>Count: {count}</p>;
}React context provider for scoped atom stores.
/**
* Provider component for scoped atom stores
* @param props - Component props
* @param props.children - React children
* @param props.store - Optional custom store, creates new one if not provided
* @returns ReactElement with store context
*/
function Provider(props: {
children?: ReactNode;
store?: Store;
}): ReactElement<
{ value: Store | undefined },
FunctionComponent<{ value: Store | undefined }>
>;Usage Examples:
import { Provider, createStore, atom, useAtom } from "jotai";
const countAtom = atom(0);
function App() {
return (
<Provider>
<Counter />
</Provider>
);
}
// With custom store
function AppWithCustomStore() {
const myStore = createStore();
return (
<Provider store={myStore}>
<Counter />
</Provider>
);
}
function Counter() {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount((c) => c + 1)}>+</button>
</div>
);
}Hook for accessing the current store context.
/**
* Hook for accessing the current store context
* @param options - Optional configuration with custom store
* @returns The current store instance
*/
function useStore(options?: Options): Store;
interface Options {
store?: Store;
}Usage Examples:
import { useStore, atom } from "jotai";
const countAtom = atom(0);
function MyComponent() {
const store = useStore();
const handleDirectAccess = () => {
// Direct store access (not recommended for normal use)
const currentCount = store.get(countAtom);
store.set(countAtom, currentCount + 1);
};
return (
<button onClick={handleDirectAccess}>
Direct Store Access
</button>
);
}
// Using custom store
function MyComponentWithCustomStore() {
const customStore = createStore();
const store = useStore({ store: customStore });
// Store operations...
}Configuration options for hooks.
interface Options {
/** Optional custom store to use instead of context store */
store?: Store;
}Type for atom setter functions returned by hooks.
type SetAtom<Args extends unknown[], Result> = <A extends Args>(
...args: A
) => Result;React-specific types used by components and hooks.
type ReactNode = React.ReactNode;
type ReactElement<P = any, T = any> = React.ReactElement<P, T>;
type FunctionComponent<P = {}> = React.FunctionComponent<P>;import { Suspense } from "react";
import { atom, useAtomValue } from "jotai";
const asyncDataAtom = atom(async () => {
const response = await fetch("/api/data");
return response.json();
});
function AsyncComponent() {
const data = useAtomValue(asyncDataAtom);
return <div>{JSON.stringify(data)}</div>;
}
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<AsyncComponent />
</Suspense>
);
}import { ErrorBoundary } from "react-error-boundary";
import { atom, useAtomValue } from "jotai";
const errorAtom = atom(async () => {
throw new Error("Something went wrong");
});
function ErrorComponent() {
const data = useAtomValue(errorAtom);
return <div>{data}</div>;
}
function App() {
return (
<ErrorBoundary fallback={<div>Error occurred!</div>}>
<Suspense fallback={<div>Loading...</div>}>
<ErrorComponent />
</Suspense>
</ErrorBoundary>
);
}import { Provider, createStore, atom, useAtom } from "jotai";
const userStore = createStore();
const appStore = createStore();
const userAtom = atom({ name: "Alice" });
const themeAtom = atom("light");
function App() {
return (
<Provider store={appStore}>
<ThemeProvider />
<Provider store={userStore}>
<UserProfile />
</Provider>
</Provider>
);
}
function ThemeProvider() {
const [theme, setTheme] = useAtom(themeAtom);
return (
<div className={`theme-${theme}`}>
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Toggle Theme
</button>
</div>
);
}
function UserProfile() {
const [user, setUser] = useAtom(userAtom);
return (
<div>
<p>User: {user.name}</p>
<button onClick={() => setUser({ name: "Bob" })}>
Change User
</button>
</div>
);
}