结合使用react useState和useLoaderData会抛出无限循环错误

问题描述 投票:0回答:2

初始情况: 我有一个元素“root”,它在每次调用时检查用户是否经过身份验证。我目前正在尝试新的 React-Router V6 并遇到了所谓的“加载器”。如果我现在通过加载器进行 API 调用,然后想要使用 useState 在元素中设置变量。我收到无限循环错误。

我的 main.jsx(定义路由的地方):

import './index.css'

import React from 'react'
import ReactDOM from 'react-dom/client'

import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import authLoader from './loader/AuthLoader'

// -- route elements --
import Root from './routes/root/root'
import Login from './routes/login/login'


const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    loader: authLoader
  },
  {
    path: "/login",
    element: <Login />
  }
], {basename: "/"})

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>,
)

我的AuthLoader.js(API调用的加载器函数):

import { API_HOST } from "../config"

const authLoader = async () => {
  return await fetch(`${API_HOST}/auth/me`, {
    credentials: 'include'
  })
}

export default authLoader

最后是我的 root.jsx

import { useState } from "react"
import { Outlet, useLoaderData } from "react-router-dom"
import { UserContext } from "../../context/UserContext"

const Home = () => {
  // states
  const [user, setUser] = useState()

  const auth = useLoaderData()

  if(auth.success) {
    /**
     * This is not working and throws an infinite loop error
     */
    setUser(auth.data.user)
  }
  
  return (
    <UserContext.Provider value={{user, setUser}}>  
      <Outlet/>
    </UserContext.Provider>
  )
}

export default Home

如果我插入

console.log
而不是
setUser(auth.data.user)
,我会得到我期望的响应。但是,当我尝试使用 useState 设置响应中显示的值时,我收到以下错误消息。

有人可以帮助我解决该错误,或者至少解释一下为什么我会收到此错误吗?

非常感谢。

javascript reactjs react-hooks react-router react-router-dom
2个回答
0
投票

这可能对你有用:

  ...
  // states
  const [user, setUser] = useState()

  useEffect(() => {
    const auth = useLoaderData()

    if(auth.success) {
      setUser(auth.data.user)
    }
  },[])

  
  return (
  ...

当您添加带有空依赖项数组的 useEffect 挂钩时,代码将仅在应用程序第一次渲染后执行一次。


0
投票

您应该永远不在组件的渲染阶段改变状态。此外,您的组件可以使您的应用程序处于不一致的状态;你可以调用

setUser
,这将使
user
auth.data.user
具有不同的值。此外,您不需要在这里使用状态。您也不需要
useEffect
;如果你有一个
useEffect
只是为了更新状态,那么你使用的钩子是错误的。

我的建议是将你的组件重写为:

const Home = () => {
  const auth = useLoaderData()
  const userContext = useMemo(() => ({
    get user() {
      return auth.success ? auth.data.user : null;
    } 
    logout() {
      // implement this, should invalidate current user session 
    } 
  }), [auth]); // only updates this memo when auth changes
  
  return (
    <UserContext.Provider value={userContext}>  
      <Outlet/>
    </UserContext.Provider>
  )
}
© www.soinside.com 2019 - 2024. All rights reserved.