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

如何在列表项内渲染Route,点击Link展开子组件?

优化你的路由展开列表组件

你的基础方案思路是对的,但大概率会遇到两个常见问题:一是未激活的<li>里的Route其实也会被挂载(只是不渲染内容),如果Topic组件比较复杂会有性能损耗;二是缺少视觉上的展开反馈,用户点击后不知道哪个项是当前激活的。

我给你两种优化思路,结合React Router的Hooks来实现更优雅的效果:

方案一:用路由参数控制激活状态与组件渲染

这种方式更轻量化,直接通过路由参数判断哪个项需要展开并渲染子组件:

import { Link, Route, useRouteMatch, useParams } from 'react-router-dom';

const Topics = () => {
  // 获取当前路由的path和url,替代props传递的match
  const { path, url } = useRouteMatch();
  // 获取路由中的topic路径参数(需要你在父路由里定义为/:topicPath)
  const { topicPath } = useParams();

  return (
    <div>
      <h2>Topics</h2>
      <ul>
        {topics.map(topic => {
          // 判断当前项是否为激活状态
          const isExpanded = topic.path === topicPath;
          return (
            <li 
              key={topic.id}
              // 给激活项加样式类,控制展开效果
              className={isExpanded ? 'topic-item expanded' : 'topic-item'}
            >
              <Link to={`${url}/${topic.path}`}>{topic.title}</Link>
              {/* 只有激活时才渲染Topic组件,减少不必要的组件挂载 */}
              {isExpanded && <Topic topic={topic} />}
            </li>
          );
        })}
      </ul>
    </div>
  );
};

方案二:保留Route但配合render prop(更符合路由驱动思想)

如果你更倾向于用Route来控制组件渲染,可以用render prop传递数据,同时结合路由匹配判断激活状态:

import { Link, Route, useRouteMatch, useLocation } from 'react-router-dom';

const Topics = () => {
  const { path, url } = useRouteMatch();
  const location = useLocation();

  return (
    <div>
      <h2>Topics</h2>
      <ul>
        {topics.map(topic => {
          const topicRoutePath = `${path}/${topic.path}`;
          const isExpanded = location.pathname === topicRoutePath;
          return (
            <li 
              key={topic.id}
              className={isExpanded ? 'topic-item expanded' : 'topic-item'}
            >
              <Link to={`${url}/${topic.path}`}>{topic.title}</Link>
              {/* 用render prop传递topic数据,避免组件不必要的重新挂载 */}
              <Route 
                path={topicRoutePath}
                render={() => <Topic topic={topic} />}
              />
            </li>
          );
        })}
      </ul>
    </div>
  );
};

加上展开样式(关键视觉反馈)

不管用哪种方案,都需要CSS来实现展开的动画效果,比如:

.topic-item {
  max-height: 2.5rem; /* 默认只显示链接的高度 */
  overflow: hidden;
  transition: max-height 0.3s ease-in-out;
  border-bottom: 1px solid #eee;
  padding: 0.5rem;
}

.topic-item.expanded {
  max-height: 20rem; /* 设置足够容纳子组件的高度 */
  background-color: #f8f9fa;
}

为什么原有方案需要优化?

你的初始代码虽然能运行,但:

  • 所有<li>里的Route都会被初始化,哪怕路由不匹配,Topic组件的构造函数/useEffect都会执行,浪费性能;
  • 没有激活状态的样式,用户无法直观看到哪个项是当前展开的;
  • 用component prop传递的话,每次路由匹配都会重新创建Topic组件实例,而用render prop可以避免这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:30:44