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

useEffect依赖location.state初始渲染未触发,如何向Outlet子组件传异步数据?

解决方案:从父组件向Outlet默认路由传递异步数据

问题根源

初始渲染Test.js时,是直接匹配路由规则进入的,并非通过带state的Link跳转,因此location.state为空;只有通过Link导航(包括从其他路由返回)时,state才会被携带。以下是几种可靠的实现方案:


方案一:使用React Context传递(推荐,灵活通用)

适合需要在组件树中共享数据的场景,异步数据加载完成后自动同步到子组件。

1. 在App.js中创建并提供Context

import { createContext, useState, useEffect } from 'react';
import { Outlet, Link } from 'react-router-dom';

// 创建Context
export const TestDataContext = createContext(null);

function App() {
  const [asyncData, setAsyncData] = useState(null);

  // 模拟异步数据请求
  useEffect(() => {
    setTimeout(() => {
      setAsyncData({ id: 1, content: '异步加载的测试数据' });
    }, 1000);
  }, []);

  return (
    <div>
      <Link to="">Render test</Link>
      <Link to="/dummy" style={{ marginLeft: '10px' }}>Dummy</Link>
      {/* 用Provider包裹Outlet,传递数据 */}
      <TestDataContext.Provider value={asyncData}>
        <Outlet />
      </TestDataContext.Provider>
    </div>
  );
}

export default App;

2. 在Test.js中获取Context数据

import { useContext } from 'react';
import { TestDataContext } from './App';

function Test() {
  const testData = useContext(TestDataContext);

  // 处理数据未加载完成的状态
  if (!testData) {
    return <div>加载中...</div>;
  }

  return <div>获取到的数据:{testData.content}</div>;
}

export default Test;

方案二:使用React Router的Loader函数(路由级数据传递)

React Router v6+ 官方推荐的路由专属数据获取方式,数据在路由渲染前加载,避免组件内的异步请求逻辑。

1. 配置路由时添加Loader

// 路由配置文件(如routes.js)
import { createBrowserRouter } from 'react-router-dom';
import App from './App';
import Test from './Test';
import Dummy from './Dummy';

// 异步获取数据的Loader函数
async function testLoader() {
  // 模拟API请求
  const res = await new Promise(resolve => {
    setTimeout(() => resolve({ id: 1, content: '从Loader获取的异步数据' }), 1000);
  });
  return res;
}

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    children: [
      // 默认路由绑定Loader
      { index: true, element: <Test />, loader: testLoader },
      { path: 'dummy', element: <Dummy /> },
    ],
  },
]);

export default router;

2. 在Test.js中获取Loader数据

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

function Test() {
  const testData = useLoaderData();

  if (!testData) {
    return <div>加载中...</div>;
  }

  return <div>获取到的数据:{testData.content}</div>;
}

export default Test;

方案三:通过navigate主动补充state(局限性大,不推荐)

仅适用于不需要保留刷新后数据的场景,因为location.state在页面刷新后会丢失。

// App.js
import { useState, useEffect } from 'react';
import { Outlet, Link, useLocation, useNavigate } from 'react-router-dom';

function App() {
  const [asyncData, setAsyncData] = useState(null);
  const location = useLocation();
  const navigate = useNavigate();

  useEffect(() => {
    setTimeout(() => {
      setAsyncData({ id: 1, content: '异步数据' });
    }, 1000);
  }, []);

  // 数据加载完成后,若当前是默认路由且无state,主动跳转补充state
  useEffect(() => {
    if (asyncData && location.pathname === '/' && !location.state) {
      navigate('/', { state: { data: asyncData }, replace: true });
    }
  }, [asyncData, location, navigate]);

  return (
    <div>
      <Link to="" state={{ data: asyncData }}>Render test</Link>
      <Link to="/dummy" style={{ marginLeft: '10px' }}>Dummy</Link>
      <Outlet />
    </div>
  );
}

export default App;

方案对比

  • Context方案:灵活通用,支持多组件共享数据,页面刷新后重新请求数据,无额外路由依赖。
  • Loader方案:路由级数据获取,数据在路由渲染前加载,逻辑与路由绑定,适合路由专属数据。
  • navigate补充state:局限性大,刷新后数据丢失,仅适合临时场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:01:02