> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/TanStack/store/llms.txt
> Use this file to discover all available pages before exploring further.

# React

> Use TanStack Store in React applications

TanStack Store provides first-class React support through the `@tanstack/react-store` package, which uses React's `useSyncExternalStore` hook for optimal performance and automatic re-rendering.

## Installation

Install the React adapter package:

<CodeGroup>
  ```bash npm theme={null}
  npm install @tanstack/react-store
  ```

  ```bash pnpm theme={null}
  pnpm add @tanstack/react-store
  ```

  ```bash yarn theme={null}
  yarn add @tanstack/react-store
  ```

  ```bash bun theme={null}
  bun add @tanstack/react-store
  ```
</CodeGroup>

<Note>
  The `@tanstack/react-store` package re-exports everything from `@tanstack/store`, so you only need to install the React package.
</Note>

## Basic Usage

The primary way to use TanStack Store in React is through the `useStore` hook:

```tsx theme={null}
import { createStore, useStore } from '@tanstack/react-store'

// Create a store
const counterStore = createStore({
  count: 0,
})

function Counter() {
  // Subscribe to the entire store state
  const count = useStore(counterStore, (state) => state.count)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => counterStore.setState((prev) => ({ count: prev.count + 1 }))}>
        Increment
      </button>
    </div>
  )
}
```

## The useStore Hook

The `useStore` hook subscribes your component to store updates and automatically triggers re-renders when selected state changes.

### Signature

```tsx theme={null}
function useStore<TState, TSelected>(
  store: Atom<TState> | ReadonlyAtom<TState>,
  selector: (state: TState) => TSelected,
  compare?: (a: TSelected, b: TSelected) => boolean
): TSelected
```

### Parameters

* `store` - The store instance to subscribe to
* `selector` - A function that selects which part of the state you need
* `compare` - (Optional) A custom equality function to determine if the selected value has changed. Defaults to `Object.is`

### Selector Optimization

The selector function allows you to subscribe to only the parts of state you need. Your component will only re-render when the selected value changes:

```tsx theme={null}
import { createStore, useStore } from '@tanstack/react-store'

const appStore = createStore({
  user: { name: 'Alice', age: 30 },
  settings: { theme: 'dark', notifications: true },
})

function UserProfile() {
  // Only re-renders when user.name changes
  const userName = useStore(appStore, (state) => state.user.name)

  return <h1>Welcome, {userName}!</h1>
}

function SettingsPanel() {
  // Only re-renders when settings change
  const settings = useStore(appStore, (state) => state.settings)

  return (
    <div>
      <p>Theme: {settings.theme}</p>
      <p>Notifications: {settings.notifications ? 'On' : 'Off'}</p>
    </div>
  )
}
```

## Custom Equality Functions

For complex state selections, you can provide a custom equality function to prevent unnecessary re-renders:

```tsx theme={null}
import { createStore, useStore } from '@tanstack/react-store'

const todoStore = createStore({
  todos: [
    { id: 1, text: 'Buy groceries', completed: false },
    { id: 2, text: 'Walk the dog', completed: true },
  ],
})

function deepEqual<T>(a: T, b: T): boolean {
  return JSON.stringify(a) === JSON.stringify(b)
}

function TodoList() {
  // Use deep equality to compare arrays
  const activeTodos = useStore(
    todoStore,
    (state) => state.todos.filter((todo) => !todo.completed),
    deepEqual
  )

  return (
    <ul>
      {activeTodos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}
```

## Shallow Equality

The package exports a `shallow` utility for shallow object comparison:

```tsx theme={null}
import { createStore, useStore, shallow } from '@tanstack/react-store'

const userStore = createStore({
  profile: { name: 'Alice', email: 'alice@example.com' },
  preferences: { theme: 'dark' },
})

function UserCard() {
  // Only re-renders if profile properties change (not the object reference)
  const profile = useStore(userStore, (state) => state.profile, shallow)

  return (
    <div>
      <h2>{profile.name}</h2>
      <p>{profile.email}</p>
    </div>
  )
}
```

The `shallow` function works with:

* Plain objects
* Maps
* Sets
* Dates
* Symbol keys

## Complete Example: Todo App

Here's a complete example demonstrating store creation, updates, and React integration:

```tsx theme={null}
import { createStore, useStore } from '@tanstack/react-store'
import { useState } from 'react'

interface Todo {
  id: number
  text: string
  completed: boolean
}

interface TodoState {
  todos: Todo[]
  filter: 'all' | 'active' | 'completed'
}

const todoStore = createStore<TodoState>({
  todos: [],
  filter: 'all',
})

// Actions
const addTodo = (text: string) => {
  todoStore.setState((state) => ({
    ...state,
    todos: [
      ...state.todos,
      { id: Date.now(), text, completed: false },
    ],
  }))
}

const toggleTodo = (id: number) => {
  todoStore.setState((state) => ({
    ...state,
    todos: state.todos.map((todo) =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ),
  }))
}

const setFilter = (filter: TodoState['filter']) => {
  todoStore.setState((state) => ({ ...state, filter }))
}

function TodoApp() {
  const [input, setInput] = useState('')
  const filter = useStore(todoStore, (state) => state.filter)
  const todos = useStore(todoStore, (state) => {
    const { todos, filter } = state
    if (filter === 'active') return todos.filter((t) => !t.completed)
    if (filter === 'completed') return todos.filter((t) => t.completed)
    return todos
  })

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    if (input.trim()) {
      addTodo(input)
      setInput('')
    }
  }

  return (
    <div>
      <h1>Todo App</h1>
      
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="What needs to be done?"
        />
        <button type="submit">Add</button>
      </form>

      <div>
        <button onClick={() => setFilter('all')}>All</button>
        <button onClick={() => setFilter('active')}>Active</button>
        <button onClick={() => setFilter('completed')}>Completed</button>
      </div>

      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
              {todo.text}
            </span>
          </li>
        ))}
      </ul>
    </div>
  )
}

export default TodoApp
```

## React-Specific Considerations

### Concurrent Features

The React adapter uses `useSyncExternalStore` under the hood, which means it's fully compatible with React 18's concurrent features including:

* Concurrent rendering
* Automatic batching
* Transitions
* Suspense (when combined with proper error boundaries)

### Server-Side Rendering (SSR)

TanStack Store works seamlessly with SSR. Create stores outside of components and initialize them with your server-side data:

```tsx theme={null}
import { createStore } from '@tanstack/react-store'

// Create the store at module level
const appStore = createStore({
  data: null,
  isLoading: false,
})

// Initialize with SSR data
export function initializeStore(initialData: any) {
  appStore.setState({ data: initialData, isLoading: false })
}
```

### Performance Tips

1. **Use selectors wisely**: Select only what you need to minimize re-renders
2. **Leverage equality functions**: Use `shallow` or custom comparisons for complex objects
3. **Memoize selectors**: For expensive computations, consider memoizing your selector functions
4. **Create multiple stores**: Instead of one large store, create multiple smaller stores for different domains

## Derived Stores

You can create derived stores that automatically update based on other stores:

```tsx theme={null}
import { createStore, useStore } from '@tanstack/react-store'

const countStore = createStore(0)
const doubleStore = createStore(() => ({ value: countStore.state * 2 }))

function CounterDisplay() {
  const count = useStore(countStore, (state) => state)
  const double = useStore(doubleStore, (state) => state.value)

  return (
    <div>
      <p>Count: {count}</p>
      <p>Double: {double}</p>
      <button onClick={() => countStore.setState((prev) => prev + 1)}>
        Increment
      </button>
    </div>
  )
}
```

## API Reference

For detailed API documentation, see:

* [useStore](/api/react/use-store) - React hook for subscribing to stores
* [shallow](/api/react/shallow) - Shallow equality comparison utility
* [createStore](/api/core/create-store) - Core store creation API

## TypeScript Support

The React adapter provides full TypeScript support with automatic type inference:

```tsx theme={null}
import { createStore, useStore } from '@tanstack/react-store'

interface AppState {
  user: { name: string; id: number }
  isAuthenticated: boolean
}

const store = createStore<AppState>({
  user: { name: '', id: 0 },
  isAuthenticated: false,
})

function Component() {
  // TypeScript knows the exact shape of state
  const userName = useStore(store, (state) => state.user.name)
  // userName is typed as string
  
  return <div>{userName}</div>
}
```
