I'm using React and I've got a Redux-Toolkit (RTK) state slice that is persisted with localStorage (I'm using the redux-persist
library). Simplified it's like that:
const initLocations = []
const locationsPersistentSlice = createSlice({
{
name: "locations",
initLocations,
reducers: {
addLocation(prevState, action) {
// adding new location to store
},
clearLocations() {
return []
}
}
})
It works synchronously and perfectly fine.
But, I want to add second slice, locationInfoSlice
, that should fetch data when addLocation()
action is dispatched, using the very last location in the list.
How can I achieve that? I thought about extraReducers
or asyncThunk
, but didn't get it right.
But, I want to add second slice
locationInfoSlice
, that should fetch data whenaddLocation()
action is dispatched, using the very last location in the list.
If I'm understanding your post/question correctly you effectively want to dispatch some single action and do the following:
state.locations
arraystate.locations
array.How can I achieve that? I thought about
extraReducers
orasyncThunk
, but didn't get it right.
You'll likely need to use both. extraReducers
alone won't work since reducer functions are pure synchronous functions without side-effects, e.g. they can't fetch data asynchronously. My suggestion would be to create a Thunk that dispatches the addLocation
action to update the state.locations
state, and also makes the data fetch you need that can return a value that will be used to update the locationInfoSlice
's state in extraReducers
.
import { createAsyncThunk } from '@reduxjs/toolkit';
import { addLocation } from '../locationsPersistentSlice';
export const addLocationAsync = createAsyncThunk(
"locations/addLocationAsync",
async (location, thunkApi) => {
// dispatch to add new location
thunkApi.dispatch(addLocation(location));
try {
// asynchronous fetch logic
return data;
} catch(error) {
return thunkApi.rejectWithError(error);
}
},
);
import { createSlice } from '@reduxjs/toolkit';
const initialState = [];
const locationsPersistentSlice = createSlice({
name: "locations",
initialState,
reducers: {
addLocation(state, action) {
state.push(action.payload);
},
clearLocations() {
return initialState;
},
},
});
export const {
addLocation,
clearLocations,
} = locationsPersistentSlice.actions;
export default locationsPersistentSlice.reducer;
import { createSlice } from '@reduxjs/toolkit';
import { addLocationAsync } from './action';
const initialState = /* whatever this initial state value is */;
const locationInfoSlice = createSlice({
name: "locationInfo",
initialState,
extraReducers: builder => {
builder
.addCase(addLocationAsync.fulfilled, (state, action) => {
// update state with fetched data
})
.addCase(addLocationAsync.rejected, (state, action) => {
// update state with error status???
})
.addCase(addLocationAsync.pending, (state, action) => {
// set any pending/loading state
});
},
});
export default locationInfoSlice.reducer;
In the UI instead of dispatching the addLocation
action directly it will now dispatch the addLocationAsync
action.
import { useDispatch } from 'react-redux';
import { addLocationAsync } from './action';
...
const dispatch = useDispatch();
...
dispatch(addLocationAsync(/* some location value */));
...