728x90
반응형
00. BreadCrumb.tsx
import { useLocation, Link } from 'react-router-dom';
function BreadCrumb() {
const location = useLocation();
const { pathname, search } = location;
const pathSegments = pathname.split('/').filter((segment) => segment);
const searchSegments = search
.replace('?', '')
.split('&')
.filter((segment) => segment);
return (
<nav aria-label="breadcrumb" className="flex items-center gap-2 text-gray-600">
<Link to="/" className="hover:text-blue-500">
Home
</Link>
{/* 경로에 따른 BreadCrumb */}
{pathSegments.map((segment, index) => {
const pathToSegment = `/${pathSegments.slice(0, index + 1).join('/')}`;
const isLastSegment = index === pathSegments.length - 1;
return (
<span key={`path-${index}`} className="flex items-center">
<span className="mx-2">/</span>
{isLastSegment ? (
<span className="text-gray-500">{decodeURIComponent(segment)}</span>
) : (
<Link to={pathToSegment} className="hover:text-blue-500">
{decodeURIComponent(segment)}
</Link>
)}
</span>
);
})}
{/* 쿼리 파라미터에 따른 BreadCrumb */}
{searchSegments.map((segment, index) => {
const queryToSegment = `?${searchSegments.slice(0, index + 1).join('&')}`;
const isLastQuery = index === searchSegments.length - 1;
return (
<span key={`query-${index}`} className="flex items-center">
<span className="mx-2">/</span>
{isLastQuery ? (
<span className="text-gray-500"> {decodeURIComponent(segment)}</span>
) : (
<Link to={queryToSegment} className="hover:text-blue-500">
{decodeURIComponent(segment)}
</Link>
)}
</span>
);
})}
</nav>
);
}
export default BreadCrumb;
01. Router 설정
import './App.css';
import './index.css';
import { Route, Routes } from 'react-router-dom';
import Home from './Home';
import Layout from './Layout';
import { RecoilRoot } from 'recoil';
function App() {
return (
<>
<RecoilRoot>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/test" element={<Layout />} />
<Route path="/test/*" element={<Layout />} />
</Routes>
</RecoilRoot>
</>
);
}
export default App;
02.Layout.tsx
import Aside from './components/url/Aside';
import Content from './Content';
function Layout() {
return (
<div className="flex gap-2 m-2">
<Aside />
<Content />
</div>
);
}
export default Layout;
03.Aside.tsx
import { NavLink } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { selectedDataAtom } from '../../store/selectedData';
function Aside() {
const [selectedData, setSelectedData] = useRecoilState(selectedDataAtom);
const handleClick = (data: string) => {
if (selectedData.includes(data)) return;
setSelectedData((prev) => [...prev, data]);
};
const context = 'http://12345/test.tsx';
const decode = encodeURIComponent(context);
return (
<div>
<ul>
<NavLink to={`/test/${decode}/1`} className=" [&.active]:text-indigo-600 text-gray-600">
<p onClick={() => handleClick('1')} className="w-[200px] text-center">
1
</p>
</NavLink>
<NavLink to={`/test/${decode}/2`} className=" [&.active]:text-indigo-600 text-gray-600">
<p onClick={() => handleClick('2')} className="w-[200px] text-center">
2
</p>
</NavLink>
</ul>
</div>
);
}
export default Aside;
04. Content.tsx
import { useLocation, useNavigate } from 'react-router-dom';
import BreadCrumb from './BreadCrumb';
import { useRecoilState } from 'recoil';
import { selectedDataAtom } from './store/selectedData';
function Content() {
const [selectedData, setSelectedData] = useRecoilState(selectedDataAtom);
const location = useLocation();
const { pathname, search } = location;
const navigate = useNavigate();
const params = new URLSearchParams(search);
const handleClick = (item: string) => {
// 현재 pathname을 '/'로 분리하여 배열로 나눔
const pathSegments = pathname.split('/');
// 마지막 경로(예: "2")를 변경
pathSegments[pathSegments.length - 1] = item;
// 새로운 pathname을 생성
const newPathname = pathSegments.join('/');
// 기존 쿼리 문자열은 그대로 유지
navigate(`${newPathname}${search}`);
};
return (
<div>
<BreadCrumb />
<div className="flex gap-1">
{selectedData.map((item) => {
return (
<ul key={item}>
<li className="bg-slate-300 text-center w-[50px] " onClick={() => handleClick(item)}>
{' '}
{item}
</li>
</ul>
);
})}
</div>
</div>
);
}
export default Content;
끝.
반응형
'React' 카테고리의 다른 글
[React] Chart.js (0) | 2025.01.01 |
---|---|
[React] Filter + React-hook-form (0) | 2024.12.22 |
[React] 드래그 가능한 사이즈 조절 컴포넌트 구현 (2) | 2024.09.22 |
페이지네이션 (0) | 2024.08.12 |
리액트 폴더구조 : 재귀적으로 컴포넌트 구조 (0) | 2024.07.28 |