CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jotai

Primitive and flexible state management for React applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

react-integration.mddocs/

React Integration

React hooks and components for integrating Jotai atoms with React applications. These provide the primary interface for using atoms in React components.

Capabilities

useAtom Hook

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>
  );
}

useAtomValue Hook

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>
  );
}

useSetAtom Hook

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>;
}

Provider Component

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>
  );
}

useStore Hook

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...
}

Types and Interfaces

Hook Options

Configuration options for hooks.

interface Options {
  /** Optional custom store to use instead of context store */
  store?: Store;
}

SetAtom Type

Type for atom setter functions returned by hooks.

type SetAtom<Args extends unknown[], Result> = <A extends Args>(
  ...args: A
) => Result;

React Types

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>;

Advanced Usage Patterns

Conditional Rendering with Suspense

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>
  );
}

Error Boundaries with Async Atoms

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>
  );
}

Multiple Stores

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>
  );
}

docs

core-atoms.md

index.md

react-integration.md

react-utilities.md

vanilla-utilities.md

tile.json