初始情况: 我有一个元素"根",它在每次调用时判断用户是否经过身份验证.我目前正在试用新的Reaction-RoutV6,遇到了所谓的"装载器".如果我现在通过加载器进行API调用,然后希望使用useState在元素中设置一个变量.我得到一个无限循环错误.

My 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>,
)

My 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),我会得到预期的结果.但是,只要我try 使用useState来设置出现在响应中的值,就会收到以下错误消息.

Error message

有没有人能帮我纠正这个错误,或者至少解释一下我为什么会出现这个错误?

非常感谢.

推荐答案

您应该在组件的呈现阶段对状态进行neverMutations .此外,您的组件允许将应用程序置于不一致的状态;您可以调用setUser,这将使userauth.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
  
  useEffect(() => {
    if (!auth.success) {
      // redirect to /login here
    }
  }, [auth]);

  return (
    <UserContext.Provider value={userContext}>  
      <Outlet/>
    </UserContext.Provider>
  )
}

更新

我强烈建议使用react-query,比如:

const Home = () => {
  const queryClient = useQueryClient()

  // directly use the async function you provided in your answer, here
  const auth = useQuery({
    queryKey: ['auth'], 
    queryFn: authLoader
  );

  // create a new async function to sever user connection
  const signoutMutation = useMutation({
    mutationFn: signoutLoader, {
    onSuccess: () => {
      // re-run authLoader, and update auth
      queryClient.invalidateQueries('auth')
    }
  )

  const userContext = useMemo(() => ({
    get user() {
      return !auth.isLoading && !auth.isError 
        ? auth.data.user 
        : null
    } 
    logout() {
      signoutMutation()
    } 
  }), [auth, signoutMutation])
  
  useEffect(() => {
    // if no user, then redirect
    if (!userContext.user) {
      // redirect to /login here
    }
  }, [userContext]);

  return (
    <UserContext.Provider value={userContext}>  
      <Outlet/>
    </UserContext.Provider>
  )
}

Javascript相关问答推荐

有Angular 的material .未应用收件箱中的价值变化

将json数组项转换为js中的扁平

如何从URL获取令牌?

JS,当你点击卡片下方的绿色空间,而它是在它的背后转动时,

在浏览器中触发插入事件时检索编码值的能力

让chart.js饼图中的一个切片变厚?

以编程方式聚焦的链接将被聚焦,但样式不适用

AddEventListner,按键事件不工作

使用Document.Evaluate() Select 一个包含撇号的HTML元素

在表单集中保存更改时删除';禁用';

使用自动识别发出信号(&Q)

使用RxJS from Event和@ViewChild vs KeyUp事件和RxJS主题更改输入字段值

在渲染turbo流之后滚动到元素

P5JS-绘制不重叠的圆

在高位图中显示每个y轴系列的多个值

Chrome上的印度时区名S有问题吗?

如何设置时间选取器的起始值,仅当它获得焦点时?

是否有静态版本的`instanceof`?

将字符串解释为数字;将其重新编码为另一个基数

:host::ng-Deep不将样式应用于material 复选框