reactjs - Reducers vs ExtraReducers som ett sätt att hantera thunks
Jag håller för närvarande på att konvertera en gammal Redux-kodbas till att använda Redux-Toolkit (RTK), och jag verkar inte kunna förstå skillnaden mellan dessa tillvägagångssätt. Tänk på denna slice:
interface MyState {
someItems: string[];
}
const myInitialState: MyState = {
someItems: []
};
const mySlice = createSlice({
name: 'mySlice',
initialState: myInitialState,
reducers: {
setItems(state, action: PayloadAction<string[]>) {
state.someItems = action.payload;
}
},
extraReducers: builder => {
builder.addCase(fetchItems.fulfilled, (state, action) => {
state.someItems = action.payload;
});
}
});
Mitt traditionella sätt att använda redux har varit att kalla på reducer direkt från en Thunk, men jag ser att sättet som definieras i extraReducers också är möjligt.
const fetchItems = createAppAsyncThunk(
'mySlice/fetchItems',
async (_, thunkAPI) => {
try {
//Get data from backend
const response = await getItems();
//Option 1
thunkAPI.dispatch(mySlice.actions.setItems(response));
//Option 2
return response;
} catch (e) {
return thunkAPI.rejectWithValue('failed');
}
}
);
Vad är skillnaden mellan dessa tillvägagångssätt? Är någon av dem att föredra framför den andra? Slutligen, när jag gör ändringar måste jag ofta ladda om data för de senaste uppdateringarna. Den här gången tror jag att jag måste använda dispatch inne i Thunk. Eller finns det alternativ?
const editItem = createAppAsyncThunk<void, string>(
'mySlice/fetchItems',
async (changedValue, thunkAPI) => {
try {
//Send data to backend
await sendSomethingToBackend(changedValue);
thunkAPI.dispatch(fetchItems());
} catch (e) {
return thunkAPI.rejectWithValue('failed');
}
}
);
Svar #1
Givet :
const fetchItems = createAppAsyncThunk( 'mySlice/fetchItems', async (_, thunkAPI) => { try { //Get data from backend const response = await getItems(); // Option 1 thunkAPI.dispatch(mySlice.actions.setItems(response)); // Option 2 return response; } catch (e) { thunkAPI.rejectWithValue('failed'); } } );Vad är skillnaden mellan dessa tillvägagångssätt?
I det stora hela finns det inte mycket skillnad mellan de två när det gäller det enskilda mySlice-tillståndssegmentet. Den största skillnaden handlar om vad, eller var, som kan hantera de "lösta" thunks.
Skicka en explicit åtgärd:
thunkAPI.dispatch(mySlice.actions.setItems(response));- Endast
mySlicesetItems-reducerfunktionen kan svara på och hantera denna åtgärd.
- Endast
Skicka en implicit uppfylld (fulfilled) åtgärd: return response;
- Alla Redux-Toolkit (RTK) slice's
extraReducers-funktioner kan reagera på och hanterafetchItems.fulfilled-åtgärden.
Föredras någon av dem över den andra?
Detta är subjektivt, men att använda Thunks .pending, .fulfilled och .rejected åtgärder är troligen den allmänt accepterade föredragna metoden eftersom det ger större flexibilitet. Ett av de främsta målen med RTK var att minska mängden kod du behövde skriva själv. Att använda de automatiskt genererade Thunk-åtgärderna är en del av detta mål.
const editItem = createAppAsyncThunk<void, string>( 'mySlice/fetchItems', async (changedValue, thunkAPI) => { try { //Send data to backend await sendSomethingToBackend(changedValue); thunkAPI.dispatch(fetchItems()); } catch (e) { thunkAPI.rejectWithValue('failed'); } } );Slutligen, när jag gör ändringar måste jag ofta ladda om datan för de senaste uppdateringarna. Den här gången tror jag att jag MÅSTE använda dispatch inuti thunk.
Ja, här skulle du absolut behöva skicka fetchItems-åtgärden för att hämta data igen som sendSomethingToBackend kan ha uppdaterat i backend.
Eller finns det alternativ?
Om du hämtar och uppdaterar data kan ett alternativ för dig vara att använda Redux-Toolkit Query (RTK Query). Du skulle skapa en API-slice som hanterar queries och mutations. Konvertera fetchItems-Thunk till en query, och editItem-Thunk till en mutation, och genom att använda cache-taggar kan mutationerna ogiltigförklara frågade data och automatiskt trigga queries att hämta om. Med andra ord, ytterligare minskning av koden du skriver.
