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

ReactJS中点击按钮切换URL并渲染对应组件的实现方案

问题:Manage Items页面路由与组件渲染不同步

我有一个Manage Items页面,可在表格中查看条目,表格包含Edit和Delete两个操作按钮。需求是:点击Edit/Delete按钮时,渲染对应的Edit/Delete组件,同时URL变为manage-items/edit/1或manage-items/edit?id=1这类格式。

当前基础URL为:manage-items
期望的URL格式:

  • 编辑URL:manage-items/edit/1或manage-items/edit?id=1
  • 删除URL:manage-items/delete/1或manage-items/delete?id=1

我尝试了以下代码:

const ManageItems = () => {
...
    return (
        <div>
            {edit ? <Routes> <Route path="/edit/:itemId" element={<EditItem itemId={itemId}/>} /> </Routes>
            : delete ? <Routes> <Route path="/delete/:itemId" element={<DeleteItem itemId={itemId}/>} /> </Routes>
            : <ItemTable items={items}/>}
        </div>
    );
};

当edit和delete两个标志都为false时,我能看到条目表格,但点击按钮后,Edit或Delete组件都不渲染,URL也没有变化,页面仅显示空白。如果移除<Routes>和<Route>,可以看到对应的Edit和Delete组件,但URL仍然没有变化。

需要实现点击按钮时同步修改URL的功能。

其他相关代码如下:

const App = () => {
  return (
    <div id="App" className="app-wrapper">
      <div>
        <Suspense fallback={<Loader />}>
          <ErrorBoundary FallbackComponent={ErrorFallback}>
            <Routes>
              {/* public routes */}
              <Route path={PORTAL_PATH_BASE} element={<Login />} />
              <Route
                path={PORTAL_PATH_UNAUTHORIZED}
                element={<ErrorFallback error={COMMON_ERRORS.unauthorized} />}
              />
              <Route
                path={PORTAL_PATH_PAGENOTFOUND}
                element={<ErrorFallback error={COMMON_ERRORS.pageNotFound} />}
              />
              <Route
                path={PORTAL_PATH_LOGINCALLBACK}
                element={<LoginCallback />}
              />
              {/* we want to protect these routes */}
              <Route element={<RequireAuth />}>
                <Route
                  path={`${PORTAL_PATH_BASE}/*`}
                  element={
                    <WithAxios>
                      <MyAdmin />
                    </WithAxios>
                  }
                />
              </Route>
            </Routes>
          </ErrorBoundary>
        </Suspense>
      </div>
    </div>
  );
};


const MyAdmin = () => {
  const { pathname } = useLocation();
  const [headerNavItems, setHeaderNavItems] = useState();

  useEffect(() => {
    let headerMenuCodes =
      JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS.UserInfo)).menu.map(
        (m) => m.menuCode
      ) || [];
    setHeaderNavItems(
      NAV_ITEM_LIST.filter(
        (hdr) => headerMenuCodes.includes(hdr.key) || hdr.key === "XY"
      )
    );
  }, []);

  return (
    <div>
      <CustomHeader navItemList={headerNavItems} />
      <PageBanner
        Title={
          MANAGE_ROUTES.find((route) => route.path === pathname)
            ?.title
        }
      >
        <CustomBreadcrumb />
      </PageBanner>
      <ScrollToTop>
        <Routes>
          <Route path={PORTAL_SUB_PATH_HOME} element={<Home />} />
          <Route
            path={`${PORTAL_SUB_PATH_BPR}/*`}
            element={<BuildingProgress />}
          />
          <Route path={`${PORTAL_SUB_PATH_MANAGE}/*`} element={<ManageItems />} />
          <Route path={`${PORTAL_SUB_PATH_RPT}/*`} element={<Settings />} />
          <Route path="*" element={<PageNotFound />} />
        </Routes>
      </ScrollToTop>
    </div>
  );
};

const DeleteItem = ({itemId}) => {
    ... load item in readonly fields and allow to confirm delete ...
}

const ItemTable = ({items, onEdit, onDelete}) => {
    ... Show table of items with two action buttons as Edit and Delete ...
}

const EditItem = ({itemId}) => {
    ... load item in editable fields and allow to save change ...
}

解决方案

你的问题核心是没有正确结合React Router的路由跳转与组件渲染逻辑,当前的条件渲染和嵌套路由写法有误,导致URL和组件状态不同步。以下是修正步骤:

1. 调整ManageItems组件的路由结构

去掉条件渲染包裹的<Routes>,直接在ManageItems内部声明完整的子路由,由路由自动控制组件渲染:

import { Routes, Route } from 'react-router-dom';

const ManageItems = () => {
  return (
    <div>
      <Routes>
        {/* 默认显示列表页 */}
        <Route index element={<ItemTable />} />
        {/* 编辑路由,使用URL路径参数 */}
        <Route path="edit/:itemId" element={<EditItem />} />
        {/* 删除路由 */}
        <Route path="delete/:itemId" element={<DeleteItem />} />
      </Routes>
    </div>
  );
};

2. 修改EditItem/DeleteItem组件获取参数

使用useParams从URL中自动获取itemId,无需手动传递:

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

const EditItem = () => {
  const { itemId } = useParams();
  // 用itemId加载对应数据并渲染编辑表单
  return (
    // 编辑表单内容
  );
};

const DeleteItem = () => {
  const { itemId } = useParams();
  // 用itemId加载待删除数据并渲染确认界面
  return (
    // 删除确认内容
  );
};

3. 修改ItemTable中的按钮跳转逻辑

使用useNavigate实现点击按钮时修改URL,同步触发路由匹配与组件渲染:

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

const ItemTable = ({ items }) => {
  const navigate = useNavigate();

  const handleEdit = (itemId) => {
    // 跳转到编辑页,URL变为manage-items/edit/[itemId]
    navigate(`edit/${itemId}`);
  };

  const handleDelete = (itemId) => {
    // 跳转到删除页,URL变为manage-items/delete/[itemId]
    navigate(`delete/${itemId}`);
  };

  return (
    <table>
      {/* 表格列定义 */}
      {items.map(item => (
        <tr key={item.id}>
          <td>{item.name}</td>
          {/* 其他数据列 */}
          <td>
            <button onClick={() => handleEdit(item.id)}>Edit</button>
            <button onClick={() => handleDelete(item.id)}>Delete</button>
          </td>
        </tr>
      ))}
    </table>
  );
};

4. 可选:支持查询参数格式(如manage-items/edit?id=1)

如果需要使用查询参数而非路径参数,修改如下:

  • 跳转逻辑:
const handleEdit = (itemId) => {
  navigate(`edit?id=${itemId}`);
};
  • 获取参数:
import { useSearchParams } from 'react-router-dom';

const EditItem = () => {
  const [searchParams] = useSearchParams();
  const itemId = searchParams.get('id');
  // ...后续逻辑
};
  • 路由定义保持:<Route path="edit" element={<EditItem />} />

原代码失效原因

  1. 条件渲染的edit/delete状态未与URL关联,点击按钮后URL无变化,路由无法匹配对应组件,导致页面空白。
  2. 嵌套路由使用了绝对路径/edit/:itemId,而ManageItems的父路由是manage-items/*,应该使用相对路径edit/:itemId才能正确匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 03:07:13