You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Express认证系统中fetchUser Action重复调用问题求助

React+Express认证系统:fetchUser Action被调用两次的问题

我基于React和Express开发认证系统时遇到问题:Redux DevTools显示fetchUser action被调用了两次。已经尝试移除useEffect的所有依赖,但问题依然存在。相关代码如下:

App组件

function App() 
{
   const [isAuth,setisAuth]=useState(false)
   const [isLoading,setIsLoading]=useState(true)
   
   const dispatch=useDispatch()
   useEffect(()=>{
         const token=localStorage.getItem('token')
         console.log("Dans useEffect")
         async function getUser(){
               try {
                   await dispatch(fetchUser())
                   setisAuth(true) 
                   setIsLoading(false)
               } catch (error)  { 
                  console.log(error)
                  return
               }
         }
   
         token? getUser():setIsLoading(false)
   },[dispatch])

 function Relog(arg){
   setisAuth(arg)
 }

 if(isLoading){
    return <div className="container d-flex justify-content-center align-items-center" style={{height:'90vh'}}>
            {console.log('Je suis dans mon rendu loading')}
            <Loading/>
           </div>
 }

  return (
    <authContext.Provider value={{isAuth,Relog}}>
       {console.log('Je suis dans mon rendu App')}
      <Router >
         <Header/>
         <Switch>
               <Route exact path='/' component={MovieList}/>
               <Route exact path='/movie/:movieId' component={MovieDetail}/>
               <PrivateRoute exact path='/favoris' component={FavoriteList}/>
               <Route exact path='/search' component={SearchResult}/>
               <Route exact path='/signin' component={Auth}/>
               <Route exact path='/test' component={Test}/>
               <Route component={PageNotFound}/>
         </Switch>
      </Router>
   </authContext.Provider>
  );
}

export default App;

fetchUser Action

export function fetchUser(){
    console.log('Fectch user action')
    return async(dispatch)=>{
       try 
       {
            const res=await fetch(`http://127.0.0.1:5000/api/auth/verify`,{
                headers:{
                    'Authorization':`Bearer ${localStorage.getItem('token')}`
                },
                method:'get'
            })
            const data=await res.json()
            if(data.error) throw data.error
           dispatch({type:FETCH_USER,payload:data.user})
       } catch (error) {
           throw error
       }
    }
}

验证Token接口

router.get('/verify',auth,(req,res)=>{
  return res.status(200).json({user:req.user})
})

认证中间件

module.exports = async(req, res, next) => {
   try {
       const header=req.headers.authorization;
       if(!header) return res.status(401).json({error:{message:"Erreur d'authentification,Veuillez vous connecter"}})
       const token =  header.split(' ')[1];
       const decodedToken = jwt.verify(token, process.env.SECRET);
       const user=await User.findByPk(decodedToken.userId)
       if(!user) throw new Err('Erreur d\'authentification',404)
       if(user.blocked) throw new Err('Votre compte est inactif pour le moment',404)
       req.user=user
       req.auth = {...decodedToken};
    
       next();
   } catch(error) 
   {
        if(error instanceof jwt.JsonWebTokenError) return res.status(401).json({error:{message:error.message}});
        next(error)
   }
};

问题排查与解决方案

1. React Strict Mode 双重渲染(最常见原因)

开发环境下,React的<StrictMode>会刻意重复调用useEffect、组件函数等,目的是检测潜在的副作用问题。这会导致你的useEffect执行两次,进而触发两次fetchUser。

  • 验证方式:检查项目入口文件(通常是index.js),看是否用<React.StrictMode>包裹了<App />。
  • 处理方案:
    • 生产环境下该问题会自动消失,无需额外处理;
    • 若要在开发环境临时避免,可移除<StrictMode>包裹,但不推荐——Strict Mode能帮你提前发现很多隐蔽的bug。

2. 标记执行状态,避免重复调用

如果需要确保fetchUser只执行一次,可通过useRef标记是否已经完成初始化:

useEffect(()=>{
  const token=localStorage.getItem('token')
  const hasFetched = useRef(false);

  async function getUser(){
    if(hasFetched.current) return;
    hasFetched.current = true;
    
    try {
      await dispatch(fetchUser())
      setisAuth(true) 
      setIsLoading(false)
    } catch (error)  { 
      console.log(error)
      setIsLoading(false)
      return
    }
  }

  token? getUser():setIsLoading(false)
},[dispatch])

3. 检查是否有其他触发源

排查其他组件或action中是否也调用了fetchUser,比如Header组件或者PrivateRoute的权限校验逻辑,是否存在重复触发的情况。


内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:57:54