-
-
Save reboottime/c8cf0d4a1faead851f046d13f22a8946 to your computer and use it in GitHub Desktop.
redux createSlice
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; | |
import { RootState, AppThunk } from "redux/store"; | |
import { fetchCount } from "services/counters"; | |
export interface CounterState { | |
value: number; | |
status: "idle" | "loading" | "failed"; | |
} | |
const initialState: CounterState = { | |
value: 0, | |
status: "idle", | |
}; | |
// The function below is called a thunk and allows us to perform async logic. It | |
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This | |
// will call the thunk with the `dispatch` function as the first argument. Async | |
// code can then be executed and other actions can be dispatched. Thunks are | |
// typically used to make async requests. | |
export const incrementAsync = createAsyncThunk( | |
"counter/fetchCount", | |
async (amount: number) => { | |
const response = await fetchCount(amount); | |
// The value we return becomes the `fulfilled` action payload | |
return response.data; | |
} | |
); | |
export const counterSlice = createSlice({ | |
name: "counter", | |
initialState, | |
// The `reducers` field lets us define reducers and generate associated actions | |
reducers: { | |
increment: (state) => { | |
// Redux Toolkit allows us to write "mutating" logic in reducers. It | |
// doesn't actually mutate the state because it uses the Immer library, | |
// which detects changes to a "draft state" and produces a brand new | |
// immutable state based off those changes | |
state.value += 1; | |
}, | |
decrement: (state) => { | |
state.value -= 1; | |
}, | |
// Use the PayloadAction type to declare the contents of `action.payload` | |
incrementByAmount: (state, action: PayloadAction<number>) => { | |
state.value += action.payload; | |
}, | |
}, | |
// The `extraReducers` field lets the slice handle actions defined elsewhere, | |
// including actions generated by createAsyncThunk or in other slices. | |
extraReducers: (builder) => { | |
builder | |
.addCase(incrementAsync.pending, (state) => { | |
state.status = "loading"; | |
}) | |
.addCase(incrementAsync.fulfilled, (state, action) => { | |
state.status = "idle"; | |
state.value += action.payload; | |
}) | |
.addCase(incrementAsync.rejected, (state) => { | |
state.status = "failed"; | |
}); | |
}, | |
}); | |
export const { increment, decrement, incrementByAmount } = counterSlice.actions; | |
// The function below is called a selector and allows us to select a value from | |
// the state. Selectors can also be defined inline where they're used instead of | |
// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)` | |
export const selectCount = (state: RootState) => state.counter.value; | |
// We can also write thunks by hand, which may contain both sync and async logic. | |
// Here's an example of conditionally dispatching actions based on current state. | |
export const incrementIfOdd = | |
(amount: number): AppThunk => | |
(dispatch, getState) => { | |
const currentValue = selectCount(getState()); | |
if (currentValue % 2 === 1) { | |
dispatch(incrementByAmount(amount)); | |
} | |
}; | |
export default counterSlice.reducer; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment