Skip to main content
Glama
redux-toolkit.ts3.8 kB
import { configureStore, createSlice, PayloadAction, createAsyncThunk, combineReducers } from '@reduxjs/toolkit'; import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; // ============================================ // Types // ============================================ interface User { id: string; name: string; email: string; } interface AuthState { user: User | null; token: string | null; status: 'idle' | 'loading' | 'succeeded' | 'failed'; error: string | null; } interface CounterState { value: number; } // ============================================ // Async Thunks // ============================================ export const loginUser = createAsyncThunk( 'auth/login', async (credentials: { email: string }, { rejectWithValue }) => { try { // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)); if (credentials.email === 'error@example.com') throw new Error('Login failed'); return { user: { id: '1', name: 'John Doe', email: credentials.email }, token: 'fake-jwt-token' }; } catch (error: any) { return rejectWithValue(error.message); } } ); // ============================================ // Slices // ============================================ const authSlice = createSlice({ name: 'auth', initialState: { user: null, token: null, status: 'idle', error: null, } as AuthState, reducers: { logout: (state) => { state.user = null; state.token = null; state.status = 'idle'; }, }, extraReducers: (builder) => { builder .addCase(loginUser.pending, (state) => { state.status = 'loading'; state.error = null; }) .addCase(loginUser.fulfilled, (state, action) => { state.status = 'succeeded'; state.user = action.payload.user; state.token = action.payload.token; }) .addCase(loginUser.rejected, (state, action) => { state.status = 'failed'; state.error = action.payload as string; }); }, }); const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 } as CounterState, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, incrementByAmount: (state, action: PayloadAction<number>) => { state.value += action.payload; }, }, }); // ============================================ // Store Configuration // ============================================ const rootReducer = combineReducers({ auth: authSlice.reducer, counter: counterSlice.reducer, }); export const store = configureStore({ reducer: rootReducer, devTools: process.env.NODE_ENV !== 'production', }); // ============================================ // TypeScript Helpers // ============================================ export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch; // Use these typed hooks throughout the app instead of plain `useDispatch` and `useSelector` export const useAppDispatch = () => useDispatch<AppDispatch>(); export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector; // ============================================ // Exports // ============================================ export const { logout } = authSlice.actions; export const { increment, decrement, incrementByAmount } = counterSlice.actions;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/millsydotdev/Code-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server