I have the below component:
import * as React from "react";
import {useAppDispatch, useAppSelector} from "./store/hook";
import {fetchUser} from "./store/slices/user/auth-slice";
import {useDispatch} from "react-redux";
function App() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchUser());
}, [])
const [loading, error] = useAppSelector((state: any) => [
state.auth.loading,
state.auth.error,
])
return (
<>
{loading ? (
<div
className="d-flex align-items-center justify-content-center"
style={{ height: "100vh" }}
>
<CircularProgress color="inherit" />
</div>
) : (
<Layout>
<Suspense fallback={<CircularProgress color="inherit" />}>
<Routes>
<Route path="/" element={<Navigate to="/regions/" replace />}/>
<Route path="ipam" element={<Ips />}/>
</Routes>
</Suspense>
</Layout>
)}
</>
);
}
export default App;
store/slices/user/auth-slice:
import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
import UserModel from "models/userAction";
import axios from "api/axios-base";
import {getUserDetails} from "../../../api/services";
import {useAppDispatch} from "../../hook";
export const fetchUser = createAsyncThunk('auth/user', async () => {
return getUserDetails().then((response) => {
return response.data;
}).catch(err => {
return err;
})
})
const initialState: UserModel = {
user_id: null,
email: '',
name: '',
isLoggedIn: false,
loading: false,
error: false,
}
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
Login(state: any, action: any) {
state = {
...initialState,
isLoggedIn: true
}
return state;
}
},
extraReducers: builder => {
builder
.addCase(fetchUser.pending, (state, action) => {
state = {
...initialState,
loading: true
}
return state;
})
.addCase(fetchUser.fulfilled, (state, action) => {
state = {
...initialState,
...action.payload.data,
isLoggedIn: true,
loading: false
}
return state;
})
.addCase(fetchUser.rejected, (state) => {
state = {
...initialState,
loading: false
}
return state;
});
}
});
export const authActions = authSlice.actions;
export default authSlice;
Now the issue is Ips
which is a sub-component of App, renders twice:
function Ips() {
useEffect(() => {
alert('test')
}, [])
return (
<div className={classes.Ip}>
test
</div>
);
}
export default Ips;
hence running the alert("test") twice, I found out the issue comes after this portion of code within my authSlice turns loading True then making it false, when I comemnt it, there is no re-rendering happening to take place inside Child component.
builder
.addCase(fetchUser.pending, (state, action) => {
state = {
...initialState,
loading: true
}
return state;
})
How can I prevent such re-rendering?
The problem is that you are re-rendering all app routes when calling that first fetchUser
API. The child component Ips
is not re-rendered, it is in fact remounted.
The simplest solution and IMO still correct (not a workaround): Initial value of loading
should be true
const initialState: UserModel = {
user_id: null,
email: '',
name: '',
isLoggedIn: false,
loading: true, // <--- `true` instead of `false`
error: false,
}