Exemples Zustand

Exemples de la bibliothèque de gestion d'état Zustand incluant la configuration de base, middleware, persistance et patterns avancés

Key Facts

Category
State Management
Items
2
Format Families
sample

Sample Overview

Exemples de la bibliothèque de gestion d'état Zustand incluant la configuration de base, middleware, persistance et patterns avancés This sample set belongs to State Management and can be used to test related workflows inside Elysia Tools.

💻 Store de Base Zustand typescript

🟢 simple ⭐⭐

Patterns fondamentaux de store Zustand incluant créer, mettre à jour et consommer l'état dans les composants React

⏱️ 20 min 🏷️ zustand, state-management, react, typescript
Prerequisites: React basics, TypeScript, Hooks
// Zustand Basic Store Examples
// Zustand is a small, fast, and scalable state management solution for React

// 1. Basic Counter Store
import React, { useState, useEffect, useCallback } from 'react'
import { create } from 'zustand'

interface CounterState {
  count: number
  increment: () => void
  decrement: () => void
  reset: () => void
}

const useCounterStore = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 }),
}))

// Usage in component
function Counter() {
  const { count, increment, decrement, reset } = useCounterStore()

  return (
    <div className="p-4 border rounded-lg">
      <h2 className="text-xl font-bold mb-4">Counter: {count}</h2>
      <div className="space-x-2">
        <button onClick={increment} className="px-4 py-2 bg-blue-500 text-white rounded">
          Increment
        </button>
        <button onClick={decrement} className="px-4 py-2 bg-red-500 text-white rounded">
          Decrement
        </button>
        <button onClick={reset} className="px-4 py-2 bg-gray-500 text-white rounded">
          Reset
        </button>
      </div>
    </div>
  )
}

// 2. Todo Store with CRUD Operations
interface Todo {
  id: string
  text: string
  completed: boolean
  createdAt: Date
}

interface TodoState {
  todos: Todo[]
  addTodo: (text: string) => void
  toggleTodo: (id: string) => void
  deleteTodo: (id: string) => void
  updateTodo: (id: string, text: string) => void
  clearCompleted: () => void
  completedCount: number
  totalCount: number
}

const useTodoStore = create<TodoState>((set, get) => ({
  todos: [],
  addTodo: (text: string) => {
    const newTodo: Todo = {
      id: Date.now().toString(),
      text,
      completed: false,
      createdAt: new Date(),
    }
    set((state) => ({ todos: [...state.todos, newTodo] }))
  },
  toggleTodo: (id: string) =>
    set((state) => ({
      todos: state.todos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      ),
    })),
  deleteTodo: (id: string) =>
    set((state) => ({
      todos: state.todos.filter((todo) => todo.id !== id),
    })),
  updateTodo: (id: string, text: string) =>
    set((state) => ({
      todos: state.todos.map((todo) =>
        todo.id === id ? { ...todo, text } : todo
      ),
    })),
  clearCompleted: () =>
    set((state) => ({
      todos: state.todos.filter((todo) => !todo.completed),
    })),
  get completedCount() {
    return get().todos.filter((todo) => todo.completed).length
  },
  get totalCount() {
    return get().todos.length
  },
}))

// Todo Component
function TodoList() {
  const {
    todos,
    addTodo,
    toggleTodo,
    deleteTodo,
    updateTodo,
    clearCompleted,
    completedCount,
    totalCount,
  } = useTodoStore()

  const [newTodoText, setNewTodoText] = useState('')

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

  return (
    <div className="max-w-md mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">Todo List</h1>

      <form onSubmit={handleSubmit} className="mb-4">
        <div className="flex space-x-2">
          <input
            type="text"
            value={newTodoText}
            onChange={(e) => setNewTodoText(e.target.value)}
            placeholder="Add a new todo..."
            className="flex-1 px-3 py-2 border rounded"
          />
          <button type="submit" className="px-4 py-2 bg-blue-500 text-white rounded">
            Add
          </button>
        </div>
      </form>

      <div className="mb-4 text-sm text-gray-600">
        {completedCount} of {totalCount} completed
      </div>

      <ul className="space-y-2">
        {todos.map((todo) => (
          <li key={todo.id} className="flex items-center space-x-2">
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
              className="w-4 h-4"
            />
            <input
              type="text"
              value={todo.text}
              onChange={(e) => updateTodo(todo.id, e.target.value)}
              className={`flex-1 px-2 py-1 border rounded ${
                todo.completed ? 'line-through text-gray-500' : ''
              }`}
            />
            <button
              onClick={() => deleteTodo(todo.id)}
              className="px-2 py-1 bg-red-500 text-white rounded text-sm"
            >
              Delete
            </button>
          </li>
        ))}
      </ul>

      {completedCount > 0 && (
        <button
          onClick={clearCompleted}
          className="mt-4 px-4 py-2 bg-gray-500 text-white rounded"
        >
          Clear Completed ({completedCount})
        </button>
      )}
    </div>
  )
}

// 3. Shopping Cart Store
interface CartItem {
  id: string
  name: string
  price: number
  quantity: number
  image?: string
}

interface CartState {
  items: CartItem[]
  addItem: (item: Omit<CartItem, 'quantity'>) => void
  removeItem: (id: string) => void
  updateQuantity: (id: string, quantity: number) => void
  clearCart: () => void
  getTotalPrice: () => number
  getTotalItems: () => number
  isInCart: (id: string) => boolean
}

const useCartStore = create<CartState>((set, get) => ({
  items: [],
  addItem: (item) =>
    set((state) => {
      const existingItem = state.items.find((i) => i.id === item.id)
      if (existingItem) {
        return {
          items: state.items.map((i) =>
            i.id === item.id
              ? { ...i, quantity: i.quantity + 1 }
              : i
          ),
        }
      }
      return { items: [...state.items, { ...item, quantity: 1 }] }
    }),
  removeItem: (id) =>
    set((state) => ({
      items: state.items.filter((item) => item.id !== id),
    })),
  updateQuantity: (id, quantity) =>
    set((state) => ({
      items: state.items.map((item) =>
        item.id === id ? { ...item, quantity: Math.max(1, quantity) } : item
      ),
    })),
  clearCart: () => set({ items: [] }),
  getTotalPrice: () =>
    get().items.reduce((total, item) => total + item.price * item.quantity, 0),
  getTotalItems: () =>
    get().items.reduce((total, item) => total + item.quantity, 0),
  isInCart: (id) => get().items.some((item) => item.id === id),
}))

// Cart Component
function ShoppingCart() {
  const {
    items,
    addItem,
    removeItem,
    updateQuantity,
    clearCart,
    getTotalPrice,
    getTotalItems,
  } = useCartStore()

  const sampleProducts = [
    { id: '1', name: 'Laptop', price: 999, image: '/laptop.jpg' },
    { id: '2', name: 'Mouse', price: 29, image: '/mouse.jpg' },
    { id: '3', name: 'Keyboard', price: 79, image: '/keyboard.jpg' },
  ]

  return (
    <div className="max-w-4xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">Shopping Cart</h1>

      <div className="grid md:grid-cols-2 gap-8">
        {/* Products */}
        <div>
          <h2 className="text-xl font-semibold mb-4">Products</h2>
          <div className="space-y-4">
            {sampleProducts.map((product) => (
              <div key={product.id} className="border p-4 rounded-lg">
                <div className="flex justify-between items-start">
                  <div>
                    <h3 className="font-semibold">{product.name}</h3>
                    <p className="text-gray-600">${product.price}</p>
                  </div>
                  <button
                    onClick={() => addItem(product)}
                    className="px-3 py-1 bg-blue-500 text-white rounded"
                  >
                    Add to Cart
                  </button>
                </div>
              </div>
            ))}
          </div>
        </div>

        {/* Cart */}
        <div>
          <h2 className="text-xl font-semibold mb-4">
            Cart ({getTotalItems()} items)
          </h2>

          {items.length === 0 ? (
            <p className="text-gray-500">Your cart is empty</p>
          ) : (
            <>
              <div className="space-y-2 mb-4">
                {items.map((item) => (
                  <div key={item.id} className="border p-3 rounded">
                    <div className="flex justify-between items-center">
                      <div>
                        <h4 className="font-semibold">{item.name}</h4>
                        <p className="text-gray-600">${item.price}</p>
                      </div>
                      <div className="flex items-center space-x-2">
                        <input
                          type="number"
                          min="1"
                          value={item.quantity}
                          onChange={(e) => {
                            const nextQuantity = Number(e.target.value)
                            updateQuantity(item.id, Number.isFinite(nextQuantity) ? nextQuantity : 1)
                          }}
                          className="w-16 px-2 py-1 border rounded"
                        />
                        <button
                          onClick={() => removeItem(item.id)}
                          className="px-2 py-1 bg-red-500 text-white rounded text-sm"
                        >
                          Remove
                        </button>
                      </div>
                    </div>
                    <p className="text-sm text-gray-600 mt-1">
                      Subtotal: ${(item.price * item.quantity).toFixed(2)}
                    </p>
                  </div>
                ))}
              </div>

              <div className="border-t pt-4">
                <div className="flex justify-between text-lg font-semibold">
                  <span>Total:</span>
                  <span>${getTotalPrice().toFixed(2)}</span>
                </div>
                <div className="mt-4 space-x-2">
                  <button className="px-4 py-2 bg-green-500 text-white rounded">
                    Checkout
                  </button>
                  <button
                    onClick={clearCart}
                    className="px-4 py-2 bg-gray-500 text-white rounded"
                  >
                    Clear Cart
                  </button>
                </div>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  )
}

// 4. User Authentication Store
interface User {
  id: string
  name: string
  email: string
  avatar?: string
  role: 'admin' | 'user'
}

interface AuthState {
  user: User | null
  isAuthenticated: boolean
  isLoading: boolean
  login: (email: string, password: string) => Promise<void>
  logout: () => void
  register: (name: string, email: string, password: string) => Promise<void>
  updateProfile: (data: Partial<User>) => Promise<void>
}

const useAuthStore = create<AuthState>((set, get) => ({
  user: null,
  isAuthenticated: false,
  isLoading: false,

  login: async (email: string, password: string) => {
    set({ isLoading: true })
    try {
      // Simulate API call
      await new Promise((resolve) => setTimeout(resolve, 1000))

      // Mock successful login
      const user: User = {
        id: '1',
        name: 'John Doe',
        email,
        role: 'user',
        avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e',
      }

      set({ user, isAuthenticated: true, isLoading: false })
    } catch (error) {
      set({ isLoading: false })
      throw error
    }
  },

  logout: () => {
    set({ user: null, isAuthenticated: false })
  },

  register: async (name: string, email: string, password: string) => {
    set({ isLoading: true })
    try {
      // Simulate API call
      await new Promise((resolve) => setTimeout(resolve, 1000))

      const user: User = {
        id: Date.now().toString(),
        name,
        email,
        role: 'user',
      }

      set({ user, isAuthenticated: true, isLoading: false })
    } catch (error) {
      set({ isLoading: false })
      throw error
    }
  },

  updateProfile: async (data: Partial<User>) => {
    const currentUser = get().user
    if (!currentUser) return

    try {
      // Simulate API call
      await new Promise((resolve) => setTimeout(resolve, 500))

      const updatedUser = { ...currentUser, ...data }
      set({ user: updatedUser })
    } catch (error) {
      throw error
    }
  },
}))

// Authentication Components
function LoginForm() {
  const { login, isLoading } = useAuthStore()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    try {
      await login(email, password)
    } catch (error) {
      alert('Login failed')
    }
  }

  return (
    <form onSubmit={handleSubmit} className="max-w-md mx-auto p-4">
      <h2 className="text-xl font-bold mb-4">Login</h2>
      <div className="space-y-4">
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="Email"
          className="w-full px-3 py-2 border rounded"
          required
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Password"
          className="w-full px-3 py-2 border rounded"
          required
        />
        <button
          type="submit"
          disabled={isLoading}
          className="w-full px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
        >
          {isLoading ? 'Logging in...' : 'Login'}
        </button>
      </div>
    </form>
  )
}

function UserProfile() {
  const { user, logout, updateProfile } = useAuthStore()
  const [isEditing, setIsEditing] = useState(false)
  const [editName, setEditName] = useState(user?.name || '')

  const handleUpdate = async () => {
    try {
      await updateProfile({ name: editName })
      setIsEditing(false)
    } catch (error) {
      alert('Update failed')
    }
  }

  return (
    <div className="max-w-md mx-auto p-4">
      <h2 className="text-xl font-bold mb-4">Profile</h2>

      <div className="space-y-4">
        {user?.avatar && (
          <img
            src={user.avatar}
            alt={user.name}
            className="w-20 h-20 rounded-full"
          />
        )}

        <div>
          {isEditing ? (
            <div className="flex space-x-2">
              <input
                type="text"
                value={editName}
                onChange={(e) => setEditName(e.target.value)}
                className="flex-1 px-3 py-2 border rounded"
              />
              <button
                onClick={handleUpdate}
                className="px-3 py-2 bg-green-500 text-white rounded"
              >
                Save
              </button>
              <button
                onClick={() => setIsEditing(false)}
                className="px-3 py-2 bg-gray-500 text-white rounded"
              >
                Cancel
              </button>
            </div>
          ) : (
            <div>
              <p className="font-semibold">{user?.name}</p>
              <p className="text-gray-600">{user?.email}</p>
              <p className="text-sm text-gray-500">Role: {user?.role}</p>
              <button
                onClick={() => {
                  setEditName(user?.name || '')
                  setIsEditing(true)
                }}
                className="mt-2 px-3 py-1 bg-blue-500 text-white rounded text-sm"
              >
                Edit Profile
              </button>
            </div>
          )}
        </div>

        <button
          onClick={logout}
          className="px-4 py-2 bg-red-500 text-white rounded"
        >
          Logout
        </button>
      </div>
    </div>
  )
}

💻 Patterns Avancés Zustand typescript

🟡 intermediate ⭐⭐⭐⭐

Patterns complexes Zustand incluant middleware, persistance, sélecteurs et optimisation des performances

⏱️ 40 min 🏷️ zustand, advanced, state-management, middleware
Prerequisites: Zustand basics, React hooks, TypeScript, Testing fundamentals
// Advanced Zustand Patterns

// 1. Persistence with Middleware
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface UserPreferences {
  theme: 'light' | 'dark'
  language: string
  notifications: boolean
  fontSize: 'small' | 'medium' | 'large'
}

const usePreferencesStore = create<UserPreferences>()(
  persist(
    (set) => ({
      theme: 'light',
      language: 'en',
      notifications: true,
      fontSize: 'medium',
      setTheme: (theme) => set({ theme }),
      setLanguage: (language) => set({ language }),
      toggleNotifications: () => set((state) => ({
        notifications: !state.notifications
      })),
      setFontSize: (fontSize) => set({ fontSize }),
    }),
    {
      name: 'user-preferences',
      storage: createJSONStorage(() => localStorage),
      partialize: (state) => ({
        theme: state.theme,
        language: state.language,
        fontSize: state.fontSize,
      }),
    }
  )
)

// 2. DevTools Middleware
import { devtools } from 'zustand/middleware'

interface AppStore {
  users: User[]
  posts: Post[]
  addUser: (user: User) => void
  addPost: (post: Post) => void
  removeUser: (id: string) => void
  removePost: (id: string) => void
}

const useAppStore = create<AppStore>()(
  devtools(
    (set) => ({
      users: [],
      posts: [],
      addUser: (user) => set((state) => ({
        users: [...state.users, user]
      })),
      addPost: (post) => set((state) => ({
        posts: [...state.posts, post]
      })),
      removeUser: (id) => set((state) => ({
        users: state.users.filter(user => user.id !== id)
      })),
      removePost: (id) => set((state) => ({
        posts: state.posts.filter(post => post.id !== id)
      })),
    }),
    {
      name: 'app-store',
      anonymousActionType: 'unknown',
    }
  )
)

// 3. Subscribe to Store Changes
const useLogger = () => {
  const subscribe = useAppStore.subscribe

  useEffect(() => {
    const unsubscribe = subscribe((state) => {
      console.log('Store updated:', state)
    })

    return unsubscribe
  }, [subscribe])
}

// Select specific state changes
useAppStore.subscribe(
  (state) => state.users,
  (users) => {
    console.log('Users changed:', users)
  }
)

// 4. Combining Multiple Stores
const useCombinedStore = () => {
  const preferences = usePreferencesStore()
  const cart = useCartStore()

  const getLocalizedPrice = (price: number) => {
    const formatter = new Intl.NumberFormat(preferences.language, {
      style: 'currency',
      currency: preferences.language === 'en' ? 'USD' : 'EUR',
    })
    return formatter.format(price)
  }

  return {
    ...preferences,
    ...cart,
    getLocalizedPrice,
  }
}

// 5. Async Actions with Error Handling
interface AsyncStore {
  data: any[]
  loading: boolean
  error: string | null
  fetchData: () => Promise<void>
  createItem: (item: any) => Promise<void>
  updateItem: (id: string, updates: any) => Promise<void>
  deleteItem: (id: string) => Promise<void>
  clearError: () => void
}

const useAsyncStore = create<AsyncStore>((set, get) => ({
  data: [],
  loading: false,
  error: null,

  clearError: () => set({ error: null }),

  fetchData: async () => {
    set({ loading: true, error: null })
    try {
      const response = await fetch('/api/data')
      const data = await response.json()
      set({ data, loading: false })
    } catch (error) {
      set({
        error: error instanceof Error ? error.message : 'Failed to fetch data',
        loading: false
      })
    }
  },

  createItem: async (item) => {
    set({ loading: true, error: null })
    try {
      const response = await fetch('/api/data', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(item),
      })
      const newItem = await response.json()

      set((state) => ({
        data: [...state.data, newItem],
        loading: false
      }))
    } catch (error) {
      set({
        error: error instanceof Error ? error.message : 'Failed to create item',
        loading: false
      })
    }
  },

  updateItem: async (id, updates) => {
    set({ loading: true, error: null })
    try {
      const response = await fetch(`/api/data/${id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      })
      const updatedItem = await response.json()

      set((state) => ({
        data: state.data.map(item =>
          item.id === id ? { ...item, ...updatedItem } : item
        ),
        loading: false
      }))
    } catch (error) {
      set({
        error: error instanceof Error ? error.message : 'Failed to update item',
        loading: false
      })
    }
  },

  deleteItem: async (id) => {
    set({ loading: true, error: null })
    try {
      await fetch(`/api/data/${id}`, { method: 'DELETE' })

      set((state) => ({
        data: state.data.filter(item => item.id !== id),
        loading: false
      }))
    } catch (error) {
      set({
        error: error instanceof Error ? error.message : 'Failed to delete item',
        loading: false
      })
    }
  },
}))

// 6. Custom Selectors for Performance
const useGameStore = create<GameStore>()(
  devtools(
    persist(
      (set, get) => ({
        players: [],
        enemies: [],
        items: [],
        score: 0,
        level: 1,
        health: 100,

        // Actions
        addPlayer: (player) => set((state) => ({
          players: [...state.players, player]
        })),

        spawnEnemy: (enemy) => set((state) => ({
          enemies: [...state.enemies, enemy]
        })),

        collectItem: (item) => set((state) => ({
          items: [...state.items, item],
          score: state.score + item.points
        })),

        takeDamage: (damage) => set((state) => ({
          health: Math.max(0, state.health - damage)
        })),

        levelUp: () => set((state) => ({
          level: state.level + 1,
          health: state.health + 20
        })),
      }),
      {
        name: 'game-store',
        storage: createJSONStorage(() => localStorage),
      }
    )
  )
)

// Custom selectors with memoization
const useGameSelectors = () => {
  const store = useGameStore()

  const aliveEnemies = useStore(useCallback(
    (state) => state.enemies.filter(enemy => enemy.health > 0),
    []
  ))

  const playerHealth = useStore(useCallback(
    (state) => state.health,
    []
  ))

  const isGameOver = useStore(useCallback(
    (state) => state.health <= 0,
    []
  ))

  const highScore = useStore(useCallback(
    (state) => state.score,
    []
  ))

  return {
    aliveEnemies,
    playerHealth,
    isGameOver,
    highScore,
    ...store
  }
}

// 7. Optimistic Updates
interface OptimisticStore {
  posts: Post[]
  updatePostOptimistic: (id: string, updates: Partial<Post>) => Promise<void>
  deletePostOptimistic: (id: string) => Promise<void>
}

const useOptimisticStore = create<OptimisticStore>((set, get) => ({
  posts: [],

  updatePostOptimistic: async (id, updates) => {
    const previousPosts = get().posts

    // Optimistic update
    set((state) => ({
      posts: state.posts.map(post =>
        post.id === id ? { ...post, ...updates } : post
      )
    }))

    try {
      const response = await fetch(`/api/posts/${id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      })

      if (!response.ok) {
        throw new Error('Update failed')
      }

      const updatedPost = await response.json()

      // Confirm update
      set((state) => ({
        posts: state.posts.map(post =>
          post.id === id ? updatedPost : post
        )
      }))
    } catch (error) {
      // Revert on error
      set({ posts: previousPosts })
      throw error
    }
  },

  deletePostOptimistic: async (id) => {
    const previousPosts = get().posts

    // Optimistic deletion
    set((state) => ({
      posts: state.posts.filter(post => post.id !== id)
    }))

    try {
      const response = await fetch(`/api/posts/${id}`, {
        method: 'DELETE',
      })

      if (!response.ok) {
        throw new Error('Delete failed')
      }
    } catch (error) {
      // Revert on error
      set({ posts: previousPosts })
      throw error
    }
  },
}))

// 8. Testing Zustand Stores
import { act, renderHook } from '@testing-library/react'
import { create } from 'zustand'

// Test store
interface TestStore {
  count: number
  increment: () => void
  decrement: () => void
}

const useTestStore = create<TestStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))

// Test cases
describe('useTestStore', () => {
  it('should initialize with count 0', () => {
    const { result } = renderHook(() => useTestStore())
    expect(result.current.count).toBe(0)
  })

  it('should increment count', () => {
    const { result } = renderHook(() => useTestStore())

    act(() => {
      result.current.increment()
    })

    expect(result.current.count).toBe(1)
  })

  it('should decrement count', () => {
    const { result } = renderHook(() => useTestStore())

    act(() => {
      result.current.decrement()
    })

    expect(result.current.count).toBe(-1)
  })
})

// 9. TypeScript Best Practices
interface StrictStore {
  readonly state: {
    user: User | null
    status: 'idle' | 'loading' | 'success' | 'error'
  }
  actions: {
    setUser: (user: User) => void
    clearUser: () => void
    setStatus: (status: StrictStore['state']['status']) => void
  }
}

const useStrictStore = create<StrictStore>((set) => ({
  state: {
    user: null,
    status: 'idle' as const,
  },
  actions: {
    setUser: (user) =>
      set((state) => ({
        state: { ...state.state, user }
      })),
    clearUser: () =>
      set((state) => ({
        state: { ...state.state, user: null }
      })),
    setStatus: (status) =>
      set((state) => ({
        state: { ...state.state, status }
      })),
  },
}))

// Usage with destructuring
const { state: { user, status }, actions } = useStrictStore()

// 10. Server-Side Rendering Support
import { create } from 'zustand'
import { createContext, useContext, useRef } from 'react'

// Store interface
interface Store {
  count: number
  increment: () => void
}

// Create store
const createStore = () => create<Store>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

// Context for store
const StoreContext = createContext<ReturnType<typeof createStore> | null>(null)

// Provider component
export const StoreProvider = ({ children }: { children: React.ReactNode }) => {
  const storeRef = useRef<ReturnType<typeof createStore>>()

  if (!storeRef.current) {
    storeRef.current = createStore()
  }

  return (
    <StoreContext.Provider value={storeRef.current}>
      {children}
    </StoreContext.Provider>
  )
}

// Hook to use store
export const useStore = <T>(selector: (store: Store) => T): T => {
  const store = useContext(StoreContext)

  if (!store) {
    throw new Error('useStore must be used within StoreProvider')
  }

  return useStore(store, selector)
}