React Router路由优化:点击店铺卡片后隐藏父组件仅显导航栏
React Router 路由跳转后父组件内容未隐藏的解决方案
开发背景
我开发了一个简单的React应用,从MongoDB数据库中获取HM、Amazon、Lindex等不同店铺的数据,并以带链接的卡片形式展示(核心逻辑在Boutiques.js中)。
期望效果
点击任意卡片后通过React Router跳转到对应页面:
- 点击“HM”卡片跳转到
/boutiques/HM,仅渲染导航栏和Template组件,隐藏店铺卡片列表 - 点击“Amazon”卡片跳转到
/boutiques/Amazon,逻辑同上
当前问题
点击卡片后,Template组件会直接渲染在店铺卡片下方,原有的卡片列表仍会显示,无法实现“仅显示导航栏和目标页面”的效果。
现有代码
App.js
import { BrowserRouter, Link, Route, Routes } from "react-router-dom"; import React from "react"; import "./CouponDeals.css"; import Boutiques from "./Boutiques"; import Home from './Home'; function App() { return ( <BrowserRouter> <div className="main-container"> <div className="navbar-section-container"> <div class="navbar"> <Link to="/">Hem</Link> <Link to="/boutiques">Butiker</Link> </div> </div> <Routes> <Route exact path="/" element={<Home />} /> <Route path="/boutiques/*" element={<Boutiques />} /> </Routes> </div> </BrowserRouter> ); } export default App;
Boutiques.js
import React, { useEffect, useState } from "react"; import {Link, Route, Routes } from "react-router-dom"; import axios from "./Axios"; import Template from "./Template.js"; const Boutiques = () => { const [deals, setDeals] = useState([]); useEffect(() => { async function fetchData() { const req = await axios.get("/butiker"); setDeals(req.data); } fetchData(); }, []); return ( <React.Fragment> <div className="header-section"> <h1 className="title">All Boutiques</h1> </div> <div className="card-section-container"> <div className="deals-container"> {deals.length > 0 ? ( deals.map((deal, index) => ( <div key={index} className="deal"> <div className="button-container"> <Link to={`${deal.name}`} className="butiker-button"> <img src={deal.imgUrl} alt={deal.name} /> </Link> </div> </div> )) ) : ( <p className="no-results">No results found</p> )} </div> </div> <Routes> {deals.map((deal, index) => ( <Route key={index} path={`${deal.name}`} element={<Template name={deal.name} />} /> ))} </Routes> </React.Fragment> ); }; export default Boutiques;
重构方案
核心思路是将Boutiques组件拆分为路由容器和列表展示组件,通过嵌套路由的逻辑控制不同路径下的内容渲染。
步骤1:拆分列表展示组件
创建BoutiquesList.js,将原Boutiques中的店铺卡片列表逻辑独立出来:
import React, { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import axios from "./Axios"; const BoutiquesList = () => { const [deals, setDeals] = useState([]); useEffect(() => { async function fetchData() { const req = await axios.get("/butiker"); setDeals(req.data); } fetchData(); }, []); return ( <> <div className="header-section"> <h1 className="title">All Boutiques</h1> </div> <div className="card-section-container"> <div className="deals-container"> {deals.length > 0 ? ( deals.map((deal, index) => ( <div key={index} className="deal"> <div className="button-container"> <Link to={`${deal.name}`} className="butiker-button"> <img src={deal.imgUrl} alt={deal.name} /> </Link> </div> </div> )) ) : ( <p className="no-results">No results found</p> )} </div> </div> </> ); }; export default BoutiquesList;
步骤2:修改Boutiques为路由容器
将原Boutiques组件改为仅负责嵌套路由的渲染,不再直接显示列表:
import React, { useEffect, useState } from "react"; import { Route, Routes } from "react-router-dom"; import axios from "./Axios"; import Template from "./Template.js"; import BoutiquesList from "./BoutiquesList"; const Boutiques = () => { const [deals, setDeals] = useState([]); useEffect(() => { async function fetchData() { const req = await axios.get("/butiker"); setDeals(req.data); } fetchData(); }, []); return ( <Routes> {/* 访问/boutiques时,渲染店铺列表 */} <Route index element={<BoutiquesList />} /> {/* 访问/boutiques/[店铺名]时,渲染对应Template */} {deals.map((deal, index) => ( <Route key={index} path={`${deal.name}`} element={<Template name={deal.name} />} /> ))} </Routes> ); }; export default Boutiques;
优化方案:使用动态路由参数
如果不想依赖后端返回的店铺数据生成路由,可以改用动态参数路由,这样无需等待数据加载即可匹配路径:
修改Boutiques组件的路由部分:
<Routes> <Route index element={<BoutiquesList />} /> {/* 动态匹配任意店铺名称 */} <Route path=":boutiqueName" element={<Template />} /> </Routes>
然后在Template组件中通过useParams获取店铺名称:
import { useParams } from "react-router-dom"; const Template = () => { const { boutiqueName } = useParams(); return <div>{boutiqueName}专属页面</div>; }; export default Template;
效果验证
- 访问
/boutiques:显示导航栏+店铺卡片列表 - 点击任意卡片跳转到
/boutiques/[店铺名]:仅显示导航栏+对应Template组件,原列表自动隐藏
内容的提问来源于stack exchange,提问作者Genesis
相关产品推荐
相关产品推荐

