我在Layout
组件中有一个useEffect
函数,它获取我的userData
并将其存储在redux-store
中,但它会随着每次路由更改而触发.
我希望useFffect
函数第一次运行,并且在我改变路由时不再触发。这与向服务器发送更多无用的请求是不正确的。我该怎么做呢?
Layout
组件:
import { useEffect, useState } from "react";
import Navbar from "../navbar/navbar";
import Footer from "../footer/footer";
import Head from "next/head";
import { useCookies } from "react-cookie";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { getUserData } from "../../redux/actions/Auth";
const Layout = ({ children }) => {
const [cookie, setCookie] = useCookies(["token"]);
const dispatch = useDispatch();
useEffect(() => { // this useEffect triggers every time i route !!
const { token } = cookie;
if (token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
dispatch({ type: "IS_LOGGED_IN" });
dispatch(getUserData(token));
}
}, []);
return (
<div className="layout" dir="rtl">
<Head>
<meta name="description" content="" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin="true"
/>
<link
href="https://fonts.googleapis.com/css2?family=Noto+Kufi+Arabic:wght@100;200;300;400;500;600;700;800;900&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
type="text/css"
charset="UTF-8"
href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css"
/>
<link
rel="stylesheet"
type="text/css"
href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css"
/>
</Head>
<Navbar />
{children}
<Footer />
</div>
);
};
export default Layout;
问题:
你正在使用useEffect
钩子,它在组件挂载时触发,也会在每次路由更改时触发,这是默认的,正确的useEffect
钩子的行为,因为你在Layout
组件上使用它,它会在每次路由更改时重新渲染。
解决方案:
有一些解决方案可以处理这些情况,比如在Layer
组件的父组件上实现getUserData(token)
,这样就不会在每次路由更改时重新渲染。
另一个解决方案是使用另一个状态变量来保存API调用状态。你有一个IS_LOGGED_IN
动作,可能会改变你的减速机,像这样:
case IS_LOGGED_IN:
return {
...state,
isUserLoggedIn: true
}
因此,在调度getUserData
之前,您需要在useEffect
上获取并检查这个示例属性:
const isLoggedIn = useSelector(state => state.user.isUserLoggedIn) // get isUserLoggedIn from the state
useEffect(() => {
if (!isLoggedIn) { // -----> getUserData if user is not logged in
const {token} = cookie;
if (token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
dispatch({ type: "IS_LOGGED_IN" });
dispatch(getUserData(token));
}
}
}, [isLoggedIn]);
解释:
一旦使用Layout
组件,isLoggedIn
值为false(因为用户没有登录),因此dispatch(getUserData(token))
方法将调用并获取数据。在此之后,isLoggedIn
将变为true
,因此useEffect
中的条件语句将检查它,并且不再允许再次调度getUserData
。
注意:您可能需要在reducer
上使用适当的过程进行另一个操作,以在用户登录或注销应用程序之间进行切换。