- React Router2022년 08월 04일 14시 46분 25초에 업로드 된 글입니다.작성자: 원2728x90반응형
"react-router-dom": "^6.3.0" 기준
$ npx create-react-app 프로젝트명
$ yarn add react-router-dom
Router 를 사용하기 위해 두개의 페이지를 만들어주자
components> Home.js
import React from "react"; function Home() { return ( <div> <h1>홈</h1> <p>이곳은 홈이에요. 제 집이죠</p> </div> ); }; export default Home;
About.js
import React from "react"; function About () { return ( <div> <h1>소개</h1> <p>리액트 라우터를 연습해보자</p> </div> ); } ; export default About;
src > Router.js 생성 (위치는 마음대로지만ㅇㅇ..)
import React from "react"; import {BrowserRouter, Route, Routes} from "react-router-dom"; import Home from "./components/Home"; import About from "./components/About"; function Router() { return ( <BrowserRouter> <Routes> <Route path={"/"} element={<Home />}/> <Route path={"/about"} element={<About />}/> </Routes> </BrowserRouter> ); } export default Router;
App.js
import './App.css'; import Router from "./Router"; function App () { return ( <div> <Router /> </div> ); }; export default App;
react Router 공식 문서대로 가자
# create react app npx create-react-app router-tutorial # vite npm init vite@latest router-tutorial --template react
cd router-tutorial npm install react-router-dom@6
index.js / main.jsx
먼저 앱을 브라우저 URL에 연결
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {BrowserRouter} from "react-router-dom"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <BrowserRouter> <App/> </BrowserRouter> // <React.StrictMode> // <App/> // </React.StrictMode> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
App.js
스타일은 그냥 붙인겅미
import './App.css'; import {Link} from "react-router-dom"; export default function App() { return ( <div> <h1>여긴 어디오?</h1> <nav style={{ borderBottom: "solid 1px", paddingBottom: "1rem", }} > <Link to="/">Home</Link> | {" "} <Link to="/About">Home</Link> </nav> </div> ); };
아래 처럼 URL 을 제어중!
후... 화질보소? 페이지를 나누기 위해 2개의 화면을 만들어보자
src > routers > Home.js / About.js
import React from "react"; export default function Home() { return ( <main style={{padding: "1rem 0"}}> <h2>여긴 홈이에요 제 집이죠</h2> </main> ); }
import React from "react"; export default function About() { return ( <main style={{ padding: "1rem 0"}}> <h2>여긴 나도 모르오</h2> </main> ); }
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {BrowserRouter, Route, Routes} from "react-router-dom"; import Home from "./routes/Home"; import About from "./routes/About"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <BrowserRouter> <Routes> <Route path="/" element={<App/>}> <Route path="home" element={<Home/>}/> <Route path="about" element={<About/>}/> </Route> </Routes> </BrowserRouter> // <React.StrictMode> // <App/> // </React.StrictMode> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
dㄹ
레이아웃 처리를 위해 App 경로 안에 경로를 넣음
- App의 path 인 / 가 내부의 자식들에 중첩됨
근데 여기서 링크를 암만 클릭해도 자식 화면이 안뜸
- 부모의 화면까지 렌더링 되고 있어서 부모인 App 의 화면만 나옴
> 부모 경로인 Outlet 에서 렌더링해야함
import './App.css'; import {Link, Outlet} from "react-router-dom"; export default function App() { return ( <div> <h1>여긴 어디오?</h1> <nav style={{ borderBottom: "solid 1px", paddingBottom: "1rem", }} > <Link to="/home">Home</Link> | {" "} <Link to="/About">About</Link> </nav> <Outlet /> </div> ); };
픽픽 툴 부셔버릴까 ㄹㅇ; 이렇게 하면 상위, 하위 경로 계층 구조완성
네이게이션 링크 만들기
일반적으로는 서버에서 데이터를 가져오겠지만 연습이니까 더미데이터생성
/scr > data.js
const invoices = [ { name: "Santa Monica", number: 1995, amount: "$10,800", due: "12/05/1995", }, { name: "Stankonia", number: 2000, amount: "$8,000", due: "10/31/2000", }, { name: "Ocean Avenue", number: 2003, amount: "$9,500", due: "07/22/2003", }, { name: "Tubthumper", number: 1997, amount: "$14,000", due: "09/01/1997", }, { name: "Wide Open Spaces", number: 1998, amount: "$4,600", due: "01/27/1998", }, ]; export function getInvoices() { return invoices; }
About.js
import React from "react"; import {Link} from "react-router-dom"; import {getInvoices} from "../data"; export default function About() { let invoices = getInvoices(); return ( <main style={{ padding: "1rem 0"}}> <h2>여긴 나도 모르오</h2> <div style={{display: "flex"}}> <nav style={{ borderRight: "solid 1px", padding: "1rem", }} > {invoices.map(item => ( <Link style={{display: "block", margin: "1rem 0"}} to={`/invoices/${item.number}`} key={item.number} > {item.name} </Link> ))} </nav> </div> </main> ); }
가져온 데이터를 하드코딩 할 순 없으니까
map 사용
잘 뜬다 이제 해당 링크를 눌려주면?
아무것도 안뜬다 왜냐 아무것도 없기 때문이다
근데 이런걸 처리를 해줘야한다.
잘못된 링크나, 해당 링크가 없는 경우를 처리해보자
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {BrowserRouter, Route, Routes} from "react-router-dom"; import Home from "./routes/Home"; import About from "./routes/About"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <BrowserRouter> <Routes> <Route path="/" element={<App/>}> <Route path="home" element={<Home/>}/> <Route path="about" element={<About/>}/> <Route path="*" element={ <main style={{padding: "1rem"}}> <p>여긴 아무것도 없소, 썩 돌아가시오!</p> </main> }/> </Route> </Routes> </BrowserRouter> // <React.StrictMode> // <App/> // </React.StrictMode> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
path의 * 이 친구가 경로가 일치하지 않는 경우에 등장해준다
돌아가자 화가 많이 나셨네 URL 매개변수 읽기
해당 URL 의 경로를 읽어오기 위해서는
해당 경로안에 Route를 새로 만들어야한다
아래의 코드를 보면 path: ":invoiceId" 로 설정되어 있는데 "/invoices/2005" 의 URL 의
":invoicedId" 는 2005 를 가져오는 매개변수가 된다.
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {BrowserRouter, Route, Routes} from "react-router-dom"; import Home from "./routes/Home"; import Invoices from "./routes/invoices"; import Invoice from "./routes/invoice"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <BrowserRouter> <Routes> <Route path="/" element={<App/>}> <Route path="home" element={<Home/>}/> <Route path="invoices" element={<Invoices/>}> <Route index element={ <main style={{padding: "1rem"}}> <p>Select an invoice</p> </main> } /> <Route path=":invoiceId" element={<Invoice/>}/> </Route> <Route path="*" element={ <main style={{padding: "1rem"}}> <p>여긴 아무것도 없소, 썩 돌아가시오!</p> </main> } /> </Route> </Routes> </BrowserRouter> // <React.StrictMode> // <App/> // </React.StrictMode> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
내용이 확 늘어날거임 기존의 About > invoices 로 대체
invoces
import React from "react"; import {Link, Outlet} from "react-router-dom"; import {getInvoices} from "../data"; export default function Invoices() { let invoices = getInvoices(); return ( <div style={{display: "flex"}}> <nav style={{ borderRight: "solid 1px", padding: "1rem", }} > {invoices.map(item => ( <Link style={{display: "block", margin: "1rem 0"}} to={`/invoices/${item.number}`} key={item.number} > {item.name} </Link> ))} </nav> // Outlet은 해당자리에 내부 Route가 들어갈 자리 (콘센트) <Outlet/> </div> ); }
invoice.js
위에서 설명 한 대로
:invoicedId -> params.invoicedId 가 된다.
parseInt 데이터 조회에서는 number 을 사용하는게 일반적이지만
URL 매개변수는 항상 String 임
import React from "react"; import {useParams} from "react-router-dom"; import {getInvoice} from "../data"; export default function Invoice() { let params = useParams(); console.log("매개변수 ",params) let invoice = getInvoice(parseInt(params.invoiceId, 10)); return ( <main style={{ padding: "1rem"}}> <h2>Total Due: {invoice.amount}</h2> <p> {invoice.name}: {invoice.number} </p> <p>Due Date : {invoice.due}</p> </main> ); }
data.js
const invoices = [ { name: "Santa Monica", number: 1995, amount: "$10,800", due: "12/05/1995", }, { name: "Stankonia", number: 2000, amount: "$8,000", due: "10/31/2000", }, { name: "Ocean Avenue", number: 2003, amount: "$9,500", due: "07/22/2003", }, { name: "Tubthumper", number: 1997, amount: "$14,000", due: "09/01/1997", }, { name: "Wide Open Spaces", number: 1998, amount: "$4,600", due: "01/27/1998", }, ]; export function getInvoices() { return invoices; } export function getInvoice(number) { return invoices.find((item) => item.number === number); }
getIInvoice 를 추가하여 받아온 number 와 일치하는 데이터를 찾아서 리턴
인덱스 Route에 index 활성
- 인덱스 경로는 상위 경로의 경로에 있는 상위 경로 콘센트에서 렌더링됨
- 상위 경로가 일치하지만 다른 하위 경로는 일치하지 않을 때 일치
- 상위 경로의 기본 하위 경로
- 사용자가 아직 탐색 목록의 항목 중 하나를 클릭하지 않은 경우 렌더링
아무것도 선택하지 않았을 때 인덱스 라우터가 렌더링 된 모습 선택한 경로에 매개변수를 받아서 해당 데이터를 출력 활성 링크
탐색 목록에서 링크를 보고 사용자가 보고 있는 활성 링크로 표시하는 것
Link 를 NavLink 로 바꿔서 invoice 목록에 추가해보자
Invoice.js
import React from "react"; import {Link, NavLink, Outlet} from "react-router-dom"; import {getInvoices} from "../data"; export default function Invoices() { let invoices = getInvoices(); return ( <div style={{display: "flex"}}> <nav style={{ borderRight: "solid 1px", padding: "1rem", }} > {invoices.map(item => ( <NavLink style={({ isActive }) => { return { display: "block", margin: "1rem 0", color: isActive ? "red" : "black", } }} to={`/invoices/${item.number}`} key={item.number} > {item.name} </NavLink> ))} </nav> <Outlet/> </div> ); }
Link -> NavLink
sytle -> 단순 객체에서 function 으로 변경
isActive 값으로 색상변경
// normal string <NavLink className="red" /> // function <NavLink className={({ isActive }) => isActive ? "red" : "blue"} />
className on 으로 설정도 가능
활성화가 되어 있다면 붉은색 아니라면 검은색로 설정 검색 매개변수
검색 매개변수는 URL 매개변수와 비슷하지만 URL에서 다른 위치에 있음
쿼리스트링 처럼 /login?success=1 이렇게 ㅇㅇ
React Router useSearchParams 를 사용하면 매개변수를 쉽게 읽고 조작이 가능함
useState와 거의 똑같이 동작하지만 메모리를 먹는 useState와 달리 URL 검색 매개변수에 상태를 저장하고 설정함
import React from "react"; import {Link, NavLink, Outlet, useSearchParams} from "react-router-dom"; import {getInvoices} from "../data"; export default function Invoices() { let invoices = getInvoices(); let [searchParams, setSearchParams] = useSearchParams(); return ( <div style={{display: "flex"}}> <nav style={{ borderRight: "solid 1px", padding: "1rem", }} > <input value={searchParams.get("filter") || ""} onChange={(event) => { let filter = event.target.value; if (filter) { setSearchParams({filter}); } else { setSearchParams({}); } }} /> {invoices .filter((item) => { let filter = searchParams.get("filter"); if (!filter) return true; let name = item.name.toLowerCase(); return name.startsWith(filter.toLowerCase()); }) .map((item) => ( <NavLink style={({ isActive }) => { return { display: "block", margin: "1rem 0", color: isActive ? "red" : "black", } }} to={`/invoices/${item.number}`} key={item.number} > {item.name} </NavLink> ))} </nav> <Outlet/> </div> ); }
지렸죠? - setSearchParams() 가 ?filter= dp 매개변수를 넣고 라우터를 다시 렌더링
- useSearchParams 로 URLSearchParams 나 filter 값 중 하나를 반환
- 입력 값을 필터 검색 매개변수에 설정
- 필터링
사용자 지정 동작
위에 코드를 보면 input에 목록을 필터링 한 후 해당 링크를 클릭하면 목록이 필터링 되지 않고
input과 URL에서 검색 매개변수가 지워짐
이걸 내맘대로 제어해보자
링크의 href 에 추가하여 링크를 클릭할 때 쿼리 문자열을 유지할 수 있다
React Router 에서 자체적으로 구성되어 있는 NavLink 가 그것을 해줌
useLocation, QueryNavLink
아래의 코드를 Invoices 에 암대나 넣고
function QueryNavLink({ to, ...props }) { let location = useLocation(); return <NavLink to={to + location.search} {...props} />; }
<NavLink> 를 <QureyNavLink>로 변경하면 됨
리셋 안되죠? 얘네들으 ㅣ정보가 궁금해서 log 를 찍어보았다
728x90반응형'JS Library > React' 카테고리의 다른 글
TodoList 기능 구현 (0) 2022.08.03 Context API 활용 상태 관리 (0) 2022.08.03 todolist 만들기 (0) 2022.08.03 styled-components (0) 2022.08.02 react-icons link (0) 2022.08.01 CSS Module (0) 2022.08.01 다음글이 없습니다.이전글이 없습니다.댓글