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

React Router中借助Action与Loader实现页面间数据传递问题

React Router 6 登录Action跳转后传递数据的实现方案

针对你遇到的登录Action处理完请求后,需要将用户数据传递到跳转页面的需求,以下是几种符合React Router 6设计理念的实现方案:

方案一:useActionData + 全局状态管理(Redux/Context)

这是你考虑过的思路,逻辑清晰且符合组件与数据分离的设计:

  • 登录Action仅负责调用接口并返回数据,不处理状态或跳转
  • 在Login组件中通过useActionData()获取Action返回的用户数据,更新全局状态后再跳转
  • 用户页直接从全局状态读取数据,或通过Loader从状态中提取

代码示例

登录Action:

export async function loginAction({ request }) {
  const formData = await request.formData();
  const res = await fetch('/api/login', {
    method: 'POST',
    body: formData
  });
  const userData = await res.json();
  
  if (res.ok) {
    return userData; // 将用户数据返回给组件
  }
  return { error: '登录失败,请检查账号密码' };
}

Login组件:

import { useActionData, useNavigate, Form } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { setUser } from './redux/slices/userSlice';
import { useEffect } from 'react';

export default function Login() {
  const actionData = useActionData();
  const navigate = useNavigate();
  const dispatch = useDispatch();

  // 当Action返回成功数据时,更新全局状态并跳转
  useEffect(() => {
    if (actionData && !actionData.error) {
      dispatch(setUser(actionData));
      navigate('/user');
    }
  }, [actionData, navigate, dispatch]);

  return (
    <Form method="post">
      <div>
        <label>账号:</label>
        <input type="text" name="username" required />
      </div>
      <div>
        <label>密码:</label>
        <input type="password" name="password" required />
      </div>
      <button type="submit">登录</button>
      {actionData?.error && <p style={{ color: 'red' }}>{actionData.error}</p>}
    </Form>
  );
}

用户页:

import { useSelector } from 'react-redux';

export default function User() {
  const user = useSelector(state => state.user);
  return <div>欢迎回来,{user.username}</div>;
}

方案二:React Router内置会话存储createCookieSessionStorage

如果不想依赖外部状态管理,React Router提供了内置的会话存储工具,适合临时跨页面传递数据:

  • 创建Cookie会话存储实例,将用户数据存在Cookie中(支持跨页面、刷新保留)
  • 登录Action中存储数据后执行redirect,用户页Loader读取并可选清理数据

代码示例

创建会话存储:

import { createCookieSessionStorage } from 'react-router-dom';

export const storage = createCookieSessionStorage({
  cookie: {
    name: 'user_session',
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/',
    maxAge: 86400 // 有效期1天
  }
});

登录Action:

import { redirect } from 'react-router-dom';
import { storage } from './storage';

export async function loginAction({ request }) {
  const formData = await request.formData();
  const res = await fetch('/api/login', {
    method: 'POST',
    body: formData
  });
  const userData = await res.json();
  
  if (res.ok) {
    await storage.setItem('user', JSON.stringify(userData));
    return redirect('/user');
  }
  return { error: '登录失败,请检查账号密码' };
}

用户页Loader:

import { redirect } from 'react-router-dom';
import { storage } from './storage';

export async function userLoader() {
  const userStr = await storage.getItem('user');
  if (!userStr) {
    return redirect('/login');
  }
  const userData = JSON.parse(userStr);
  // 可选:读取后删除临时存储
  await storage.removeItem('user');
  return { user: userData };
}

用户组件:

import { useLoaderData } from 'react-router-dom';

export default function User() {
  const { user } = useLoaderData();
  return <div>欢迎回来,{user.username}</div>;
}

方案三:URL查询参数(仅适合非敏感少量数据)

如果传递的是少量非敏感数据(如用户名、用户ID),可以通过URL查询参数携带,但绝对不能传递敏感信息(如token、密码):

代码示例

登录Action:

import { redirect } from 'react-router-dom';

export async function loginAction({ request }) {
  const formData = await request.formData();
  const res = await fetch('/api/login', {
    method: 'POST',
    body: formData
  });
  const userData = await res.json();
  
  if (res.ok) {
    const searchParams = new URLSearchParams({
      username: userData.username,
      userId: userData.id.toString()
    });
    return redirect(`/user?${searchParams.toString()}`);
  }
  return { error: '登录失败,请检查账号密码' };
}

用户页Loader:

import { redirect } from 'react-router-dom';

export async function userLoader({ request }) {
  const url = new URL(request.url);
  const username = url.searchParams.get('username');
  const userId = url.searchParams.get('userId');
  
  if (!username) {
    return redirect('/login');
  }
  return { username, userId };
}

方案选择建议

  • 已使用全局状态管理(如Redux):优先选择方案一,逻辑统一,符合现有技术栈
  • 无全局状态管理需求:方案二是React Router原生方案,无需额外依赖,适配性好
  • 少量非敏感数据:方案三可以快速实现,但注意数据安全性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 19:31:03