Why doesn't useEffect hook work on page refresh?
Solution 1
You might want to try adding conditional logic within the useEffect so you only trigger the dispatch if you don't already have a profile.
import "./styles.css";
import { useDispatch, useSelector } from "react-redux";
import { useEffect, useCallback } from "react";
import { getCurrentProfile } from "./action";
export const Profile = () => {
const dispatch = useDispatch();
const profileReducer = useSelector((state) => state.profile);
const authReducer = useSelector((state) => state.auth);
const { profile, error, loading } = profileReducer;
// read more about this here: https://stackoverflow.com/questions/58624200/react-hook-useeffect-has-a-missing-dependency-dispatch
const stableDispatch = useCallback(dispatch, []);
useEffect(() => {
if (!profile) {
stableDispatch(getCurrentProfile());
}
}, [profile, stableDispatch]);
const { user } = authReducer;
console.log("loading", loading);
console.log("profile", profile);
return loading && profile === null ? <div>Spinner</div> : "Actual Profile";
};
export default Profile;
Also, it doesn't seem like you're currently doing anything with the loading
piece of state–at least from what you've shared here. You might want to dispatch an action indicating that you're loading before you start the fetch and then it will be set to false when you get the response.
Check out this codesandbox for reference: https://codesandbox.io/s/focused-kilby-gd2nr?file=/src/App.js
Reducers:
const initialState = {
profile: null,
loading: false
};
export const profile = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case "LOADING_PROFILE":
return {
...state,
loading: true
};
case "GET_PROFILE":
return {
...state,
profile: payload,
loading: false
};
case "PROFILE_ERROR":
return {
...state,
error: payload,
profile: null
};
case "CLEAR_PROFILE":
return {
...state,
profile: null,
loading: false
};
default:
return state;
}
};
export const auth = (state = {}, action) => {
return state;
};
Action Creator:
import axios from "axios";
export const getCurrentProfile = () => async (dispatch) => {
try {
dispatch({ type: "LOADING_PROFILE" });
const res = await axios.get("https://jsonplaceholder.typicode.com/users/1");
console.log(res);
dispatch({
type: "GET_PROFILE",
payload: res.data.data
});
} catch (err) {
dispatch({
type: "PROFILE_ERROR",
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
index.js
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, combineReducers, applyMiddleware } from "redux";
import { profile, auth } from "./reducers";
import App from "./App";
import thunk from "redux-thunk";
const store = createStore(
combineReducers({
profile,
auth
}),
applyMiddleware(thunk)
);
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>,
rootElement
);
Solution 2
Well i solved it by dispatching 'getCurrentProfile' not 'getCurrentProfile()' turns out using it like a function causes continuously firing off.
const profileReducer = useSelector((state) => state.profile);
const authReducer = useSelector((state) => state.auth);
const { profile, error, loading } = profileReducer;
const dispatch = useDispatch();
useEffect(() => {
if (!profile) {
console.log("It worked")
dispatch(getCurrentProfile());
}
}, [dispatch(getCurrentProfile)])
hakanAkdogan
Updated on June 05, 2022Comments
-
hakanAkdogan almost 2 years
I'm working on a react project. I have my own API to fetch information. I'm using the useEffect hook to fetch profile information from API. My problem is when page mounts for the first time i can fetch the data with no problem but if i refresh the page it doesn't work at all. I know i have to give a second parameter to useEffect. I tried to put profile as the second argument even dispatched the getCurrentProfile function but when i do that it constantly fires off fetch request. I would be glad if anyone can help me with that. Thanks.
Here is my Profile component:
export const Profile = () => { const dispatch = useDispatch(); useEffect(() => { dispatch(getCurrentProfile()); }, []) const profileReducer = useSelector((state) => state.profile); const authReducer = useSelector((state) => state.auth); const { profile, error, loading } = profileReducer; const { user } = authReducer; console.log("loading", loading) console.log("profile", profile) return loading && profile === null ? ( <div > <Spinner /> </div> ) :
Here is my Profile action:
export const getCurrentProfile = () => async dispatch => { try { const res = await axios.get("/api/profile/me"); console.log(res); dispatch({ type: "GET_PROFILE", payload: res.data.data }) } catch (err) { dispatch({ type: "PROFILE_ERROR", payload: { msg: err.response.statusText, status: err.response.status } }) }
}
Here is my profile reducer:
export default (state = initialState, action) => { const { type, payload } = action; switch (type) { case "GET_PROFILE": return { ...state, profile: payload, loading: false } case "PROFILE_ERROR": return { ...state, error: payload, profile: null } case "CLEAR_PROFILE": return { ...state, profile: null, loading: false } default: return state; }
}
-
Dakota Lee Martinez about 3 yearscould you add in to the question what it was that you put into the dependency array (the second argument to useEffect) that caused it to continually fetch?
-
-
hakanAkdogan about 3 yearsSo i tried adding a conditional logic to useEffect. To do that i had to declare profileReducer before the useEffect. I put profile to dependecy array. It still works when first mounted but refreshing the page doesn't fires useEffect at all.
-
Dakota Lee Martinez about 3 yearshmm, interesting. Have you checked out the sandbox I shared? Seems like it's working on refresh there. I did also add a bit about loading to the action creator and reducer
-
hakanAkdogan about 3 yearsThanks for all your help. It turns out it was a silly mistake i made. I published the mistake i made you can check it out if you want. Sorry for stealing your time, thank you again :)
-
Dakota Lee Martinez about 3 yearsno worries! thanks for sharing the fix. I think there can be an issue sometimes with adding a function into the dependency array and that it's generally encouraged to use the useCallback hook to create a stable version of the function so it's not a new function every time. reactjs.org/docs/hooks-reference.html#usecallback