Last active
March 28, 2021 19:31
-
-
Save rahsheen/0d72bba31be3bbf977a3f17fd11a409d to your computer and use it in GitHub Desktop.
How to Break extraReducers
This file contains hidden or 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} from '../../app/store'; | |
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 | |
export const incrementAsync = createAsyncThunk( | |
'counter/fetchCount', | |
async (amount: number, {dispatch}) => { | |
await new Promise((resolve) => | |
setTimeout(() => resolve(dispatch(incrementByAmount(amount))), 1000), | |
); | |
}, | |
); | |
export const counterSlice = createSlice({ | |
name: 'counter', | |
initialState, | |
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; | |
}, | |
}, | |
/** | |
const incrementAsync: AsyncThunk<void, number, {}> | |
No overload matches this call. | |
Overload 1 of 2, '(actionCreator: AsyncThunkPendingActionCreator<number>, reducer: CaseReducer<CounterState, PayloadAction<undefined, string, { arg: number; requestId: string; requestStatus: "pending"; }, never>>): ActionReducerMapBuilder<...>', gave the following error. | |
Type 'string' is not assignable to type 'void | CounterState | WritableDraft<CounterState>'. | |
Overload 2 of 2, '(type: string, reducer: CaseReducer<CounterState, PayloadAction<undefined, string, { arg: number; requestId: string; requestStatus: "pending"; }, never>>): ActionReducerMapBuilder<...>', gave the following error. | |
Argument of type 'AsyncThunkPendingActionCreator<number>' is not assignable to parameter of type 'string'.ts(2769) | |
typings.d.ts(413, 74): The expected type comes from the return type of this signature. | |
**/ | |
extraReducers: (builder) => { | |
builder | |
// THIS IS FINE | |
.addCase(incrementAsync.pending, (state, _action) => { | |
state.status = 'loading'; | |
}) | |
// THIS SINKS MY BATTLESHIP with above TS error | |
.addCase(incrementAsync.fulfilled, (state, _action) => | |
state.status = 'idle' | |
); | |
}, | |
}); | |
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; | |
export default counterSlice.reducer; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment