MyCuppa

State Management Patterns in Cuppa

Explore different approaches to managing state in your Cuppa applications, from local state to global stores.

Cuppa Team
tutorialstate-managementbest-practices

State management is a crucial aspect of building modern applications. In this post, we'll explore different patterns for managing state in Cuppa applications.

Local Component State

For simple, component-specific state, use React's useState:

import { useState } from 'react'
import { Button } from '@mycuppa/ui'

function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={() => setCount(count + 1)}>
        Increment
      </Button>
    </div>
  )
}

Shared State with Context

For state that needs to be shared across multiple components, use React Context:

import { createContext, useContext, useState } from 'react'

const ThemeContext = createContext()

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

export function useTheme() {
  return useContext(ThemeContext)
}

Cuppa Store

For complex global state, use the built-in Cuppa Store from @mycuppa/core:

import { createStore } from '@mycuppa/core'

interface AppState {
  user: User | null
  todos: Todo[]
  isLoading: boolean
}

const store = createStore<AppState>({
  user: null,
  todos: [],
  isLoading: false,
})

// In your components
function TodoList() {
  const todos = store.useSelector(state => state.todos)

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

  return (
    <div>
      {todos.map(todo => (
        <div key={todo.id}>{todo.text}</div>
      ))}
    </div>
  )
}

Best Practices

1. Start Simple

Begin with local state (useState) and only move to global state when you actually need to share data between components.

2. Keep State Close to Where It's Used

Don't lift state higher than necessary. This keeps your components more maintainable and easier to understand.

3. Use TypeScript

Define interfaces for your state to catch errors early:

interface TodoState {
  items: Todo[]
  filter: 'all' | 'active' | 'completed'
  isLoading: boolean
}

4. Avoid Prop Drilling

If you find yourself passing props through many layers of components, consider using Context or a global store.

Examples

Want to see these patterns in action? Check out:

Learn More

For more information, check out our Core package documentation and explore the state management utilities available in Cuppa.