I'm trying to fetch data from two different API's using Redux-toolkit
, however I don't want them to be fetched simultaneously. Let's say I have two buttons and if I click on the button 1
the app should fetch data from the first api and if the click is on the button 2
the data should come from the second API.
Other thing is that the API's have different structures, so I need two different slices (or reducers). The issue is, since I'm using the same store for both reducers, both API's are being fetched.
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'
import footballReducer from 'features/tournaments/footballSlice'
import volleyballReducer from 'features/tournaments/tournamentsSlice'
export const store = configureStore({
reducer: {
matchesFootball: footballReducer, // USED TO FETCH API 1
matchesVolleyball: volleyballReducer, // USED TO FETCH API 2
}
})
export type AppDispatch = typeof store.dispatch
export type RootState = ReturnType<typeof store.getState>
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>
Is there a way where I can control which reducer will be executed?
My first thoughts were:
1- Use two different slices, one for each API and execute its respective reducer (I couldn't be sure if this last part is possible)
2- To create two stores, what would make it hard to manage, since I have only two reducers for now, but it'll increase to almost 10;
3- Use only one slice, where I would set one extra reducer
for each API data, in that case I believe I would have to create one different function for each fetch;
Is there a builtin way to do that? Or at least a more straightforward way, which wouldn't look like some bad trick?
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "store/store";
import http from "services/services";
import IVolleyballModel from "models/VoleyballModel";
export interface VolleyballState {
matches: IVolleyballModel[]
status: "success" | "loading" | "failed"
rounds: number
tournamentName: string
}
const initialState: VolleyballState = {
matches: [],
status: "loading",
rounds: 0,
tournamentName: ''
};
export const fetchMatches = createAsyncThunk(
"matchesList/fetchMatches",
async (gender: number) => {
const response = await http.getSLTable(gender);
return response.data;
}
);
export const tournamentsSlice = createSlice({
name: "matchesList",
initialState,
reducers: {
setTournamentName (state, action: PayloadAction<string>) {
state.tournamentName = action.payload
}
},
extraReducers: (builder) => {
builder
.addCase(fetchMatches.pending, (state) => {
state.status = "loading";
})
.addCase(fetchMatches.fulfilled, (state, action) => {
state.status = "success";
let allMatches: any[] = [];
let rounds: number = 0;
action.payload.grupos[0].rodadas.map((round: { jogos: [] }) => {
// ... SOME LOGIC
});
state.matches = [...allMatches];
state.rounds = rounds;
})
.addCase(fetchMatches.rejected, (state) => {
state.status = "failed";
});
},
});
export const { setTournamentName } = tournamentsSlice.actions
export const getData = (state: RootState) => state.matchesVolleyball;
export default tournamentsSlice.reducer;
You can totally do 1.
- an extraReducer for one asyncThunk will not trigger for another asyncThunk.
That said, you might also want to explore RTK-Query, which abstracts all that fetching, state keeping and storing logic away from you.
In both cases, I would recommend you read up on it in Chapters 5, 7 and 8 of the official Redux Essentials tutorial that walks you through the different approaches and shows benefits and drawbacks of both.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.