为什么 useEffect 钩子在页面刷新时不起作用?

时间:2021-04-16 23:16:29

标签: reactjs react-redux react-hooks use-effect

我正在做一个 React 项目。我有自己的 API 来获取信息。我正在使用 useEffect 钩子从 API 获取配置文件信息。我的问题是当页面第一次挂载时,我可以毫无问题地获取数据,但是如果我刷新页面,它根本不起作用。我知道我必须给 useEffect 提供第二个参数。我试图将配置文件作为第二个参数甚至调度 getCurrentProfile 函数,但是当我这样做时,它会不断触发获取请求。如果有人可以帮助我,我会很高兴。谢谢。

这是我的个人资料组件:

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

这是我的个人资料操作:

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

}

这是我的配置文件缩减器:

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

}

2 个答案:

答案 0 :(得分:1)

您可能想尝试在 useEffect 中添加条件逻辑,以便仅在您还没有配置文件时才触发分派。

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;

此外,您目前似乎没有对 loading 状态进行任何操作 - 至少从您在此处分享的内容来看是这样。您可能希望在开始获取之前调度一个指示您正在加载的操作,然后在您收到响应时将其设置为 false。

查看此代码和框以供参考:https://codesandbox.io/s/focused-kilby-gd2nr?file=/src/App.js

减速器:

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

动作创建者:

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

答案 1 :(得分:0)

好吧,我通过调度 'getCurrentProfile' 而不是 'getCurrentProfile()' 解决了这个问题,结果像函数一样使用它会导致持续触发。

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