1
+ import { createAsyncThunk , createSlice , PayloadAction } from "@reduxjs/toolkit"
2
+ import { RootState , AppThunk } from "../../app/store"
3
+ import { fetchCount } from "./CounterAPI"
4
+
5
+ export interface CounterState {
6
+ value : number
7
+ status : "idle" | "loading" | "failed"
8
+ }
9
+
10
+ const initialState : CounterState = {
11
+ value : 0 ,
12
+ status : "idle" ,
13
+ }
14
+
15
+ // The function below is called a thunk and allows us to perform async logic. It
16
+ // can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
17
+ // will call the thunk with the `dispatch` function as the first argument. Async
18
+ // code can then be executed and other actions can be dispatched. Thunks are
19
+ // typically used to make async requests.
20
+ // export const incrementAsync = createAsyncThunk(
21
+ // "counter/fetchCount",
22
+ // async (amount: number) => {
23
+ // const response = await fetchCount(amount)
24
+ // // The value we return becomes the `fulfilled` action payload
25
+ // return response.data
26
+ // },
27
+ // )
28
+
29
+ export const counterSlice = createSlice ( {
30
+ name : "counter" ,
31
+ initialState,
32
+ // The `reducers` field lets us define reducers and generate associated actions
33
+ reducers : {
34
+ increment : ( state ) => {
35
+ // Redux Toolkit allows us to write "mutating" logic in reducers. It
36
+ // doesn't actually mutate the state because it uses the Immer library,
37
+ // which detects changes to a "draft state" and produces a brand new
38
+ // immutable state based off those changes
39
+ console . log ( "increment" ) ;
40
+ state . value += 1
41
+ } ,
42
+ decrement : ( state ) => {
43
+ state . value -= 1
44
+ } ,
45
+ // Use the PayloadAction type to declare the contents of `action.payload`
46
+ incrementByAmount : ( state , action : PayloadAction < number > ) => {
47
+ state . value += action . payload
48
+ } ,
49
+ } ,
50
+ // The `extraReducers` field lets the slice handle actions defined elsewhere,
51
+ // including actions generated by createAsyncThunk or in other slices.
52
+ // extraReducers: (builder) => {
53
+ // builder
54
+ // .addCase(incrementAsync.pending, (state) => {
55
+ // state.status = "loading"
56
+ // })
57
+ // .addCase(incrementAsync.fulfilled, (state, action) => {
58
+ // state.status = "idle"
59
+ // state.value += action.payload
60
+ // })
61
+ // .addCase(incrementAsync.rejected, (state) => {
62
+ // state.status = "failed"
63
+ // })
64
+ // },
65
+ } )
66
+
67
+ export const { increment, decrement, incrementByAmount } = counterSlice . actions
68
+
69
+ // The function below is called a selector and allows us to select a value from
70
+ // the state. Selectors can also be defined inline where they're used instead of
71
+ // in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
72
+ export const selectCount = ( state : RootState ) => state . counter . value
73
+
74
+ // We can also write thunks by hand, which may contain both sync and async logic.
75
+ // Here's an example of conditionally dispatching actions based on current state.
76
+ // export const incrementIfOdd =
77
+ // (amount: number): AppThunk =>
78
+ // (dispatch, getState) => {
79
+ // const currentValue = selectCount(getState())
80
+ // if (currentValue % 2 === 1) {
81
+ // dispatch(incrementByAmount(amount))
82
+ // }
83
+ // }
84
+
85
+ export default counterSlice . reducer
0 commit comments