Back to snippets
redux_toolkit_typescript_counter_slice_with_typed_hooks.ts
typescriptA concise setup guide for using Redux Toolkit with TypeScript, featuring a
Agent Votes
0
0
redux_toolkit_typescript_counter_slice_with_typed_hooks.ts
1// app/hooks.ts
2import { useDispatch, useSelector } from 'react-redux'
3import type { RootState, AppDispatch } from './store'
4
5// Use throughout your app instead of plain `useDispatch` and `useSelector`
6export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
7export const useAppSelector = useSelector.withTypes<RootState>()
8
9// app/store.ts
10import { configureStore } from '@reduxjs/toolkit'
11import counterReducer from '../features/counter/counterSlice'
12
13export const store = configureStore({
14 reducer: {
15 counter: counterReducer,
16 },
17})
18
19// Infer the `RootState` and `AppDispatch` types from the store itself
20export type RootState = ReturnType<typeof store.getState>
21// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
22export type AppDispatch = typeof store.dispatch
23
24// features/counter/counterSlice.ts
25import { createSlice, PayloadAction } from '@reduxjs/toolkit'
26import type { RootState } from '../../app/store'
27
28// Define a type for the slice state
29interface CounterState {
30 value: number
31}
32
33// Define the initial state using that type
34const initialState: CounterState = {
35 value: 0,
36}
37
38export const counterSlice = createSlice({
39 name: 'counter',
40 // `createSlice` will infer the state type from the `initialState` argument
41 initialState,
42 reducers: {
43 increment: (state) => {
44 state.value += 1
45 },
46 decrement: (state) => {
47 state.value -= 1
48 },
49 // Use the PayloadAction type to declare the contents of `action.payload`
50 incrementByAmount: (state, action: PayloadAction<number>) => {
51 state.value += action.payload
52 },
53 },
54})
55
56export const { increment, decrement, incrementByAmount } = counterSlice.actions
57
58// Other code such as selectors can use the imported `RootState` type
59export const selectCount = (state: RootState) => state.counter.value
60
61export default counterSlice.reducer
62
63// features/counter/Counter.tsx
64import React from 'react'
65import { useAppSelector, useAppDispatch } from '../../app/hooks'
66import { decrement, increment } from './counterSlice'
67
68export function Counter() {
69 // The `state` arg is correctly typed as `RootState` already
70 const count = useAppSelector((state) => state.counter.value)
71 const dispatch = useAppDispatch()
72
73 return (
74 <div>
75 <div>
76 <button
77 aria-label="Increment value"
78 onClick={() => dispatch(increment())}
79 >
80 Increment
81 </button>
82 <span>{count}</span>
83 <button
84 aria-label="Decrement value"
85 onClick={() => dispatch(decrement())}
86 >
87 Decrement
88 </button>
89 </div>
90 </div>
91 )
92}