Skip to content

Instantly share code, notes, and snippets.

@rahsheen
Last active March 28, 2021 19:31
Show Gist options
  • Save rahsheen/0d72bba31be3bbf977a3f17fd11a409d to your computer and use it in GitHub Desktop.
Save rahsheen/0d72bba31be3bbf977a3f17fd11a409d to your computer and use it in GitHub Desktop.
How to Break extraReducers
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