'useSelector updates twice when createAsyncThunk dispatches event fulfilled
I'm new to redux toolkit and react. But I'm trying to follow the redux toolkit slicer methodology.
My slice:
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
const axios = require("axios");
export const fetchR = createAsyncThunk(
"fetchR",
async (teamId) => {
console.log(teamId);
var data = await axios.get(url);
return data.data;
}
);
export const rSlice = createSlice({
name: "slice",
initialState: {
data: { count: 0, data: [] },
loading: "",
},
reducers: {
setR: (state, action) => {},
getR: (state, action) => {},
},
extraReducers: (builder) => {
builder.addCase(fetchR.pending, (state, action) => {
state.loading = "loading";
});
builder.addCase(fetchR.fulfilled, (state, action) => {
state.data = action.payload;
state.loading = "loaded";
});
},
});
// Action creators are generated for each case reducer function
export const { setR, getR } = rSlice.actions;
export default rSlice.reducer;
My component that calls fetchR the createAsyncThunk.
<IconButton
onClick={() => {
dispatch(fetchR("FU"));
}}
type="submit"
sx={{ p: "10px" }}
aria-label="search"
>
<SearchIcon />
</IconButton>
My component that listens to state change for rSlice.
const MainSub = () => {
const rList = useSelector((state) => {
console.log(state.res);
return state.res;
}, shallowEqual);
return (
<div>
</div>
);
};
export default MainSub;
My console.log:
FU
MainSub.js:6
{res: {…}}
res: {data: {…}, loading: 'loading'}
[[Prototype]]: Object
MainSub.js:6
{res: {…}}
res: {data: {…}, loading: 'loaded'}
[[Prototype]]: Object
MainSub.js:6
{res: {…}}
res: {data: {…}, loading: 'loaded'}
[[Prototype]]: Object
Notice that the console log in MainSub runs twice when createAysncThunk dispatches fulfilled. I'm not sure what could cause this to run twice. Looking at my network traffic, there is only ONE get request made. So I know that I'm not making multiple requests. Our thunk dispatches an event to pending and fulfilled once. But useSelector thinks the state was changed twice when Thunk dispatches to fulfilled. Again this console log is happening in our MainSub component. Any help would be appreciated Thank you!
Solution 1:[1]
Yes, the selector will get run twice - once in the Redux subscription callback after the action itself is dispatched (so it runs outside of React), but then potentially again inside the component itself during render. This is due to an implementation detail of useSelector.
As a side note, you should never write useSelector(state => state) - that will always cause the component to re-render any time the root state changes! Instead, you should always select the smallest piece of state this component needs.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | markerikson |
