처음부터 시작하는 Java
  • React Router
    2022년 08월 04일 14시 46분 25초에 업로드 된 글입니다.
    작성자: 원2
    728x90
    반응형

    "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
    댓글