State Management
This page covers creating Redux slices for UI and local state management using Redux Toolkit's createSlice and createEntityAdapter.
When to Use Slices vs RTK Query
Choose the right tool for your state:
Remote data (server-owned)
RTK Query
User profiles, NFTs, catalog items, orders
UI state (client-owned)
createSlice
Filters, modals, view preferences, form state
Normalized collections
createEntityAdapter
Sorted/filtered lists, optimistic updates
Do not duplicate the same data in both a slice and RTK Query. Choose one source of truth.
Creating a Basic Slice
Use createSlice for simple UI state:
// src/features/ui/ui.slice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import type { RootState } from '@/app/store';
interface UIState {
sidebarOpen: boolean;
modalOpen: boolean;
viewMode: 'grid' | 'list';
theme: 'light' | 'dark';
}
const initialState: UIState = {
sidebarOpen: true,
modalOpen: false,
viewMode: 'grid',
theme: 'light',
};
const uiSlice = createSlice({
name: 'ui',
initialState,
reducers: {
// Boolean toggles
sidebarToggled(state) {
state.sidebarOpen = !state.sidebarOpen;
},
// Set specific value
modalOpened(state) {
state.modalOpen = true;
},
modalClosed(state) {
state.modalOpen = false;
},
// Payload actions
viewModeChanged(state, action: PayloadAction<'grid' | 'list'>) {
state.viewMode = action.payload;
},
themeChanged(state, action: PayloadAction<'light' | 'dark'>) {
state.theme = action.payload;
},
// Multiple properties
uiReset() {
return initialState;
},
},
});
// Export actions
export const {
sidebarToggled,
modalOpened,
modalClosed,
viewModeChanged,
themeChanged,
uiReset,
} = uiSlice.actions;
// Export reducer
export default uiSlice.reducer;
// Export selectors
export const selectSidebarOpen = (state: RootState) => state.ui.sidebarOpen;
export const selectModalOpen = (state: RootState) => state.ui.modalOpen;
export const selectViewMode = (state: RootState) => state.ui.viewMode;
export const selectTheme = (state: RootState) => state.ui.theme;Using Entity Adapters
For normalized collections (lists with IDs), use createEntityAdapter:
Entity Adapter Methods
State Mutations
Generated Selectors
Complex State Example
Combining multiple concerns in one slice:
Memoized Selectors
Use createSelector from Reselect for computed/derived state:
Async Logic with Extra Reducers
Handle RTK Query or async thunk responses in your slice:
Best Practices
1. Keep State Minimal
2. Use Immer-Friendly Mutations
3. Organize Reducers Logically
4. Type Actions Properly
Testing Slices
Next Steps
Review Component Patterns for using slices in components
Learn about Web3 Integration for blockchain state
See Testing & Performance for optimization tips
Last updated