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

如何在React Router 6的action函数中访问React Context数据?

在React Router v6的Action函数中访问上下文并更新用户状态

你遇到的Invalid hook call错误,本质是React Router的action函数不属于React组件或自定义钩子,不符合React钩子的调用规则——钩子只能在函数组件主体或自定义钩子的顶层调用,而action是路由层面的异步处理函数,无法直接访问React Context。

下面提供两种可行的解决方案,帮你实现登录后更新用户上下文的目标:


方案1:组件内处理状态更新,action仅负责API请求

让action专注于表单验证和API交互,返回登录结果;在登录组件中通过useActionData获取结果后,再调用上下文的setCurrentUser更新状态。

修改后的AuthAction

export const AuthAction = async ({ request }) => {
  const data = await request.formData()
  const userData = {
    email: data.get('email'),
    password: data.get('password')
  }

  if (!userData.email || !userData.password) {
    throw json(
      { message: '请填写所有字段' },
      { status: 400, statusText: '请填写所有字段' }
    )
  }

  try {
    const { data } = await axios.post('/api/auth/login', userData)
    // 返回登录成功的用户数据,而非直接操作上下文
    return json({ user: data })
  } catch (error) {
    return json({ error: error.response.data.msg }, { status: 400 })
  }
}

登录组件中处理状态更新

import { useActionData, Form, useNavigate } from 'react-router-dom'
import { useAppContext } from './appContext'
import { useEffect } from 'react'

const LoginPage = () => {
  const { setCurrentUser } = useAppContext()
  const actionData = useActionData()
  const navigate = useNavigate()

  // 监听action返回结果,更新上下文并跳转
  useEffect(() => {
    if (actionData?.user) {
      setCurrentUser(actionData.user)
      navigate('/')
    }
  }, [actionData, setCurrentUser, navigate])

  return (
    <div>
      <Form method="post">
        <input type="email" name="email" placeholder="邮箱" required />
        <input type="password" name="password" placeholder="密码" required />
        <button type="submit">登录</button>
      </Form>
      {actionData?.error && <p style={{ color: 'red' }}>{actionData.error}</p>}
    </div>
  )
}

方案2:改用全局状态管理库替代React Context

如果需要在非组件环境(如action、工具函数)中直接操作状态,React Context的组件树依赖特性会限制使用。可以改用Zustand、Redux等全局状态库,它们的状态可在任意环境访问。

用Zustand实现用户状态

// store/userStore.js
import { create } from 'zustand'

export const useUserStore = create((set) => ({
  currentUser: null,
  setCurrentUser: (user) => set({ currentUser: user })
}))

在AuthAction中直接更新状态

import { useUserStore } from '../store/userStore'

export const AuthAction = async ({ request }) => {
  // 表单数据验证逻辑同前
  const data = await request.formData()
  const userData = {
    email: data.get('email'),
    password: data.get('password')
  }

  if (!userData.email || !userData.password) {
    throw json(
      { message: '请填写所有字段' },
      { status: 400, statusText: '请填写所有字段' }
    )
  }

  try {
    const { data } = await axios.post('/api/auth/login', userData)
    // 直接调用store的更新方法,无需钩子
    useUserStore.getState().setCurrentUser(data)
    return redirect('/')
  } catch (error) {
    return json({ error: error.response.data.msg }, { status: 400 })
  }
}

组件中使用状态

import { useUserStore } from '../store/userStore'

const Navbar = () => {
  const currentUser = useUserStore(state => state.currentUser)
  return <div>当前用户:{currentUser?.email}</div>
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:27:43