State Management Patterns in Cuppa
Explore different approaches to managing state in your Cuppa applications, from local state to global stores.
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:
- Todo App Example - Local state with
useState - E-commerce Cart - Context for global cart state
- Dashboard - Complex state management patterns
Learn More
For more information, check out our Core package documentation and explore the state management utilities available in Cuppa.