Blog>
Snippets

Modular Redux with TypeScript: Type-Safe Slices

Detail the creation of feature-based slices in Redux using TypeScript's type safety features, keeping code maintainable and scalable.
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface CounterState {
  value: number;
}

const initialState: CounterState = { value: 0 };

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
This TypeScript code defines a 'counter' slice using Redux Toolkit's `createSlice` function. The state is type-safe with an interface, `CounterState`, and has an initial state. It includes three reducers: increment, decrement, and incrementByAmount, which are type-safe with the use of `PayloadAction`.
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
This code sets up a Redux store with the Redux Toolkit's `configureStore` function. It imports the `counterReducer` from the previously defined counter slice and includes it in the store. It also exports the `AppDispatch` and `RootState` types for use throughout the application.
// HTML structure
<div id="app">
  <button id="increment">Increment</button>
  <button id="decrement">Decrement</button>
  <button id="incrementByAmount">Increment by 10</button>
  <div id="value">0</div>
</div>
This HTML code defines a simple structure with three buttons for triggering different actions (increment, decrement, increment by a specific amount) and a `div` element to display the counter value.
/* CSS styles */
#app {
  text-align: center;
  margin-top: 50px;
}

button {
  margin: 5px;
}

#value {
  font-size: 2em;
  margin-top: 20px;
}
This CSS code provides basic styling for the application, centering the content, styling the buttons, and increasing the font size of the counter display.
import { store } from './store';
import { increment, decrement, incrementByAmount } from './counterSlice';

document.getElementById('increment').addEventListener('click', () => {
  store.dispatch(increment());
});

document.getElementById('decrement').addEventListener('click', () => {
  store.dispatch(decrement());
});

document.getElementById('incrementByAmount').addEventListener('click', () => {
  store.dispatch(incrementByAmount(10));
});

store.subscribe(() => {
  document.getElementById('value').innerText = store.getState().counter.value.toString();
});
This JavaScript code sets up event listeners on the buttons and dispatches the appropriate actions. It subscribes to store updates and updates the counter display with the new state.