Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't useEffect hook work on page refresh?

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;
}

}

like image 472
hakanAkdogan Avatar asked May 27 '26 22:05

hakanAkdogan


1 Answers

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
);

like image 172
Dakota Lee Martinez Avatar answered May 30 '26 15:05

Dakota Lee Martinez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!