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

React Router v6中如何向路由状态传递函数?

问题描述

点击跳转到NewUser路由时,希望在Users和NewUser两个路由间共享状态修改逻辑(setUsers)。通过Link的state传递字符串能正常访问,但传递函数时在NewUser组件中拿到的是null。不想使用Context或Redux,希望通过路由跳转的方式实现。

相关代码

Users组件

function Users() {
  const [users, setUsers] = useState([]);

  return (
      <Card sx={{ padding: "2rem", mt: "2rem" }}>
        <MDBox
          display="flex"
          flexDirection="row"
          justifyContent="space-between"
        >
          <MDTypography variant="body2">{`You currently have ${users.length} users`}</MDTypography>
          <MDButton variant="gradient" color="info" size="small">
            <Link to="/settings/users/new-user" state={{ setUsers: setUsers }}>
              <MDBox
                display="flex"
                alignItems="center"
                color="white"
                fontWeight="normal"
              >
                <Icon>add</Icon>&nbsp; Add New User
              </MDBox>
            </Link>
          </MDButton>
        </MDBox>
    </Card>
);
}

NewUser组件

function NewUser({history}) {
  const location = useLocation();
  const navigate = useNavigate();

  const saveChanges = (e) => {
    location.state.setUsers({
      fname: values.firstName,
      lname: values.lname,
      email: values.email,
    });
    navigate("/settings/users");
  };

  return(
    <MDBox py={3} mb={20} height="62vh">
        <Grid
          container
          justifyContent="center"
          alignItems="center"
          sx={{ height: "100%", mt: 0 }}
        >
          <Grid item xs={12} lg={12}>
            <Formik
              initialValues={initialValues}
              validationSchema={currentValidation}
              onSubmit={(values) => {
                setValues(values);
              }}
            >
              {({ values, errors, touched, isSubmitting }) => (
                <Form id={formId} autoComplete="off">
                  <Card sx={{ height: "100%", width: "100%" }}>
                    <MDBox px={3} py={4}>
                      <MDBox display="flex">
                        <ButtonWrapper
                          fullWidth={false}
                          handleClick={saveChanges}
                        >
                          Save Changes
                        </ButtonWrapper>
                      </MDBox>
                      <MDBox>
                        {getStepsContent({
                          values,
                          touched,
                          formField,
                          errors,
                        })}
                      </MDBox>
                    </MDBox>
                  </Card>
                </Form>
              )}
            </Formik>
          </Grid>
        </Grid>
      </MDBox>
    )
}

路由配置

[
  {
    type: "collapse",
    name: "Settings",
    key: "settings",
    icon: <Icon fontSize="small">settings</Icon>,
    collapse: [
      {
        name: "Users",
        key: "users",
        route: "/settings/users",
        component: <Users />,
      },
      {
        name: "Companies",
        key: "companies",
        route: "/settings/companies",
        component: <Companies />,
      },
      {
        name: "Billing",
        key: "billing",
        route: "/settings/billing",
        component: <Billing />,
      },
      {
        name: "Integrations",
        key: "integrations",
        route: "/settings/integrations",
        component: <Integrations />,
      },
    ],
  },
  {
    name: "New User",
    key: "new user",
    route: "/settings/users/new-user",
    noCollapse: true,
    component: <NewUser />,
  },
  {
    type: "collapse",
    name: "Sign Out",
    key: "signout",
    route: "/sign-out",
    icon: <Icon fontSize="small">logout</Icon>,
    component: <SignOut />,
    noCollapse: true,
  },
];

路由渲染函数

const getRoutes = (allRoutes) =>
  allRoutes.map((route) => {
    if (route.collapse) {
      return getRoutes(route.collapse);
    }
    if (route.route) {
      return <Route exact path={route.route} element={route.component} key={route.key} />;
    }
    return null;
  });

<Routes>
  {getRoutes(routes)}
  <Route path="*" element={<Console />} />
</Routes>

问题原因

React Router的Link组件传递的state会被序列化为JSON格式,存储在浏览器的历史记录栈中。而函数属于不可序列化的数据,无法被JSON转换,因此传递后会被浏览器自动丢弃,最终在目标路由中拿到null。

解决方案

方案1:将NewUser设为Users的子路由,通过Outlet传递上下文

这种方式可以直接将setUsers传递给子路由组件,无需依赖路由state。

  1. 修改路由配置,把NewUser设为Users的子路由:
{
  type: "collapse",
  name: "Settings",
  key: "settings",
  icon: <Icon fontSize="small">settings</Icon>,
  collapse: [
    {
      name: "Users",
      key: "users",
      route: "/settings/users",
      component: <Users />,
      collapse: [
        {
          name: "New User",
          key: "new user",
          route: "/settings/users/new-user",
          component: <NewUser />,
        },
      ],
    },
    // 其余配置不变
  ],
},
  1. 更新Users组件,使用Outlet渲染子路由并传递setUsers:
import { Outlet, Link } from 'react-router-dom';

function Users() {
  const [users, setUsers] = useState([]);

  return (
    <>
      <Card sx={{ padding: "2rem", mt: "2rem" }}>
        <MDBox
          display="flex"
          flexDirection="row"
          justifyContent="space-between"
        >
          <MDTypography variant="body2">{`You currently have ${users.length} users`}</MDTypography>
          <MDButton variant="gradient" color="info" size="small">
            <Link to="/settings/users/new-user">
              <MDBox
                display="flex"
                alignItems="center"
                color="white"
                fontWeight="normal"
              >
                <Icon>add</Icon>&nbsp; Add New User
              </MDBox>
            </Link>
          </MDButton>
        </MDBox>
      </Card>
      {/* 通过Outlet传递上下文 */}
      <Outlet context={{ setUsers }} />
    </>
  );
}
  1. 在NewUser组件中通过useOutletContext获取setUsers:
import { useOutletContext, useNavigate } from 'react-router-dom';

function NewUser() {
  const { setUsers } = useOutletContext();
  const navigate = useNavigate();

  const saveChanges = (e) => {
    // 注意:要往数组里添加新用户,不是直接替换为单个对象
    setUsers(prevUsers => [...prevUsers, {
      fname: values.firstName,
      lname: values.lname,
      email: values.email,
    }]);
    navigate("/settings/users");
  };

  // 其余代码不变
}

方案2:将状态提升到路由父组件,通过props传递

把users和setUsers提升到渲染路由的父组件,直接通过props传递给需要的路由组件。

  1. 修改路由渲染的父组件,添加状态并传递props:
import { useState } from 'react';
import { Routes, Route } from 'react-router-dom';

function AppRoutes() {
  const [users, setUsers] = useState([]);

  const getRoutes = (allRoutes) =>
    allRoutes.map((route) => {
      if (route.collapse) {
        return getRoutes(route.collapse);
      }
      if (route.route) {
        // 获取组件类型,判断是否需要传递状态
        const Component = route.component.type;
        let componentProps = {};
        if (Component === Users || Component === NewUser) {
          componentProps = { users, setUsers };
        }
        return (
          <Route
            exact
            path={route.route}
            element={<Component {...componentProps} />}
            key={route.key}
          />
        );
      }
      return null;
    });

  return (
    <Routes>
      {getRoutes(routes)}
      <Route path="*" element={<Console />} />
    </Routes>
  );
}
  1. 更新Users组件,改用props接收状态:
// 去掉组件内部的useState,改用props传入
function Users({ users, setUsers }) {
  return (
    // 其余代码不变
  );
}
  1. 更新NewUser组件,接收setUsers:
import { useNavigate } from 'react-router-dom';

function NewUser({ setUsers }) {
  const navigate = useNavigate();

  const saveChanges = (e) => {
    setUsers(prevUsers => [...prevUsers, {
      fname: values.firstName,
      lname: values.lname,
      email: values.email,
    }]);
    navigate("/settings/users");
  };

  // 其余代码不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:20:29