programming language/react

[React] React Router 파해치기

공대키메라 2022. 6. 12. 16:53

저번 시간에는 useReducer와 React Router 에 대해 간단히 알아보았다.

(궁금하면 클릭!)

 

이번 시간에는 React Router에 어떤 기능이 있는지 알아보도록 하겠다.

 

많은 기능이 있지만 최대한 내가 써먹을 수 있을 만큼 알아보도록 하겠다.

 

그럼 후비고~

 

다음 내용은 모두 React Router 홈페이지에 있으니 자세한 내용은 이곳을 참고하길 바란다.

 

출처:

https://reactrouter.com/docs/en/v6/getting-started/tutorial

https://mygumi.tistory.com/414

https://abangpa1ace.tistory.com/209

https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8

1. React Router사이트 소개

키메라는 React Router에서 제공하는 Tutorial을 통해서 어떤 기능이 있는지 학습하고 있다.

 

 

정말 많은 기능이 있고 코드도 함께 붙여서 설명해주고 있다.

 

지난 시간에 Routers에서 BrowserRouter, Components에서 Link, Route, Routes에 대해 알아보았다.

 

이번에는 어제 알아낸 기능에 더해 뭐가 좋을지 좀 더 찾아서 공부하도록 하겠다.

1. <NavLink> Component

<NavLink는 active한지 아닌지를 아는 특별한 <Link>다. 
이것은 breadcrumb(현재 내가 어디 위치인지 알려주는 것 - 예 : tistory > 공대키메라 > react) 같은 navigating 메뉴를 만들거나 현재 선택된 것을 보여주고 싶을 때 일련의 tab들을 만들 때 유용하다. 
또한, screen reader처럼 유용한 context에 도움되는 기술을 제공한다. 

출처 : https://reactrouter.com/docs/en/v6/components/nav-link

 

내가 이해하기로는 NavLink는 결국 Link에 특별한 속성을 줄 수 있는 것이다. 현재 어떤 것을 선택햇는지 파악할 수 있게 말이다.

 

지난 시간에 사용한 코드에서 약간 수정을 하였다.

Nav.js

import { Link, NavLink } from "react-router-dom";
const Nav = () => {
  let activeStyle = {
    textDecoration: "underline",
    color: "red",
  };

  let activeClassName = "underline";
  return (
    <>
      <ul>
        <li>
          <Link to={"/"}>Home</Link>
        </li>
        <li>
          <Link to={"/router1"}>Router1</Link>
        </li>
        <li>
          <Link to={"/router2"}>Router2</Link>
        </li>
        <li>
          <NavLink
            to={"/navlink"}
            style={({ isActive }) => (isActive ? activeStyle : undefined)}
          >
            NavLink
          </NavLink>
        </li>
      </ul>
    </>
  );
};

export default Nav;

 

위의 코드에서 선택시에 activeStyle 이 들어가도록 설정했다. color를 red로 변하도록 설정했는데 과연....

 

일반 nav rul 클릭시 모습

 

NavLink를 적용한 url 클릭시 모습

 

 

이렇게 변화한 것을 확인할 수 있다.

 

믿음이 부족한 키메라는 혹시 같은 component를 다른 url로 설정시에도 잘 작동할지 궁금해서 그렇게 해본 결과...

 

 

color가 선택한것만 변하니 아주 잘 작동하는것을 확인했다.

2. <Navigate> Component와 useNavigate Hook

뭔가 벌써부터 이름에서 url을 조작하는 느낌이 드는데...  좀 더 알아봐야겠다.

 

<Navigate> element는 렌더링 된 현재 주소를 바꾼다.
이건 useNavigate에 감싸인 component이고 props처럼 모든 같은 argument들을 받아들인다.

 

네비게이션이 목적지까지 우리를 안내한다면, <Navigate> element도 마찬가지로 우리를 다른 url로 안내하는 역할을 하는 것 같다. 

 

그런데 useNavigate를 감싼다고 하니 useNavigate를 찾아서 적용해보았다.

Nav.js 수정 - useNavigate적용

import { Link, NavLink, useNavigate } from "react-router-dom";
const Nav = () => {
  let activeStyle = {
    textDecoration: "underline",
    color: "red",
  };

  let navigate = useNavigate();

  const moveToHome = () => {
    navigate("/");
  };
  return (
    <>
      <ul>
        <li>
          <Link to={"/"}>Home</Link>
        </li>
        <li>
          <Link to={"/router1"}>Router1</Link>
        </li>
        <li>
          <Link to={"/router2"}>Router2</Link>
        </li>
        <li>
          <NavLink
            to={"/navlink"}
            style={({ isActive }) => (isActive ? activeStyle : undefined)}
          >
            NavLink
          </NavLink>
        </li>
        <li>
          <NavLink
            to={"/navlink2"}
            style={({ isActive }) => (isActive ? activeStyle : undefined)}
          >
            NavLink2
          </NavLink>
        </li>
        <li>
          <button onClick={moveToHome}>moveToHome!</button>
        </li>
        <li>
          <button
            onClick={() => {
              navigate(-1);
            }}
          >
            뒤로가기
          </button>
        </li>
      </ul>
    </>
  );
};

export default Nav;

 

버튼이 생성됐는데 과연.... 

 

 

moveToHome! 을 클릭하면 다음과 같이 된다. 

 

Home 으로 돌아왔다!

 

그리고 뒤로가기를 클릭하면 뒤로 갈 수 있다!

 

useNavigate에 -1을 parameter로 넣어주면 된다. 

 

 

뒤로가기를 클릭하니 조금 전에 있엇던 화면으로 돌아왔다!

 

이 useNavigate같은 경우에는 특정 이벤트를 시행했을 때, 정해진 화면으로 보내줄 때 유용할 것 같다. 

 

3. Path Variable를 위한 useParams 사용

우리가 일반적으로 web application을 개발할 때 path variable을 많이 사용한다. 

 

react router에도 그런 기능을 제공하는데 코드로 보면 이해하기 쉽다.

App.js - router1에 path variable 기능 추가

import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./Home";
import Nav from "./Nav";
import NavLinkTest from "./NavLinkTest";
import Router1 from "./Router1";
import Router2 from "./Router2";
export default function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Nav />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/router1/:param" element={<Router1 />} />
          <Route path="/router2" element={<Router2 />} />
          <Route path="/navlink" element={<NavLinkTest />} />
          <Route path="/navlink2" element={<NavLinkTest />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

Rourer1.js - useParam Hook 추가

import { useParams } from "react-router-dom";

const Router1 = () => {
  const { param } = useParams();
  console.log(param);
  return <div>router1 :: param = {param}</div>;
};

export default Router1;

 

그리고 url에 주소를 입력값을 추가해서 다음과 같이 하면...

 

우리가 받고자 하는 param을 꺼내는것을 확인할 수 있다.

 

 

3. useSearchParams를 이용한 Query String 사용

이것을 적용해보기 위해 Router2 component를 수정했다.

Rourer2.js - useSearchParams Hook 추가

import { useSearchParams } from "react-router-dom";

const Router2 = () => {
  const [searchParams, setSearchParams] = useSearchParams();

  const id = searchParams.get("id");
  const password = searchParams.get("password");
  return (
    <div>
      router2
      <br />
      {id && `아이디 : ${id}`}
      {password && `비밀번호 : ${password}`}
      <button
        onClick={() => {
          setSearchParams({ password: "expired!" });
        }}
      >
        password change!
      </button>
    </div>
  );
};

export default Router2;

 

그리고 적절한 query string을 입력해 주면 다음과 같은 화면이 나온다. 

 

 

그리고 password 버튼을 누르면 우리의 현재 query string을 바꿀 수 있다. 클릭시 password 에만 expired! 라는 param을 넣어주었다.

 

결과는 다음과 같다. 

 

 

4. useRoutes 사용하기

useRoutes hook은 <Routes>의 Functional Equivalent(함수적 등가물??) 다. 
하지만 routes를 정의하는 <Route> element 대신에 javascript 객체를 사용한다.
보통의 <Route>처럼 같은 properties를 가지는데 JSX가 필요 없다. 

출처 : https://reactrouter.com/docs/en/v6/hooks/use-routes

=> 이게 함수적 등가물이라는 표현이 <Routes>를 쓰는 것과 동일하게 작동한다는 말로 이해된다. 

 

이것을 한번 적용하려고 했는데 

 

필자의 스터디용 파일은 현재 구조 자체가 달라서 전부 수정을 해야 한다.

 

너무 귀찮은 관계로, 참고 사이트를 퍼왔다.

 

읽어보니 너무 친절해서 여기를 참고하면 될 것 같다. 

 

참고 추천 사이트 클릭!

5. 중첩 Routes 구현하기

만약에 우리가 중첩으로 url을 구성하고 싶으면 어떻게 해야할까?

 

예를 들어서 "/router2/test" 이런 식으로 url을 구성하고 싶다면?

 

다음과 같이 하면 된다

App.js - 라우팅 중첩 적용

import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./Home";
import Nav from "./Nav";
import NavLinkTest from "./NavLinkTest";
import Router1 from "./Router1";
import Router2 from "./Router2";
import Test from "./Test";
export default function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Nav />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/router1/:param" element={<Router1 />} />
          <Route path="/router2" element={<Router2 />}>
            <Route path="test" element={<Test />} />
          </Route>
          <Route path="/navlink" element={<NavLinkTest />} />
          <Route path="/navlink2" element={<NavLinkTest />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

Test.js

const Test = () => {
  return <div>test</div>;
};

export default Test;

Router2.js - Outlet 적용하기

import { Outlet, useSearchParams } from "react-router-dom";

const Router2 = ({ match }) => {
  console.log(match);
  const [searchParams, setSearchParams] = useSearchParams();

  const id = searchParams.get("id");
  const password = searchParams.get("password");
  return (
    <>
      <div>
        router2
        <br />
        {id && `아이디 : ${id}`}
        {password && `비밀번호 : ${password}`}
        <button
          onClick={() => {
            setSearchParams({ password: "expired!" });
          }}
        >
          password change!
        </button>
        <Outlet />
      </div>
    </>
  );
};

export default Router2;


여기서 <Outlet> element가 등장하는데 docs에서 다음과 같이 설명한다. 

 

<Outlet>은 부모 route elements들의 자식 router element 안에서 사용되야 한다. 
이 element는 중첩된 UI가 자식 element가 rendering될 때 나타나도록 한다. 
부모 route 가 정확이 매치된다면, 자식 index route를 render하거나 index route에 없다면 rendering하지 않을 것이다.

=> 부모 안의 component에 넣어줘야 하며, 맞으면 뿌리고, 안맞으면 안뿌리고! 로 이해된다. 

 

실행 화면은 다음과 같다. 

 

 

우선 router2를 클릭했다. <Test> component는 현재 보이지 않는게 맞다. url을 타고 가지 않았으니까!

 

그러면 이제 router2뒤에 Test를 붙여서 router2/test로 입력해보겠다.

 

 

짜잔! 중첩 라우팅이 성공했다!


오늘은 React Router에 대해서 공부해보았다.

 

다음에는 React에 Server Side Rendering을 적용해 볼 것이다. 

 

그 다음에서야 내가 이 React를 처음부터 공부한 목적인 redux란 무엇인지 공부하고, redux-thunk, redux-saga에 대해서 알아볼 것이다.