2022.10.04.
TIL

TIL

어제와 오늘 React Router에 대해서 학습했습니다. v5로 미니 프로젝트를 구현해보고 현재 가장 최신버전인 v6으로 마이그레이션을 하였습니다. v5에서 v6으로 변경된 점들을 기록합니다.


Route

v5

function App() {
  return (
    <Layout>
      <Switch>
        <Route path="/" exact>
          <Redirect to="/quotes" />
        </Route>
        <Route path="/quotes" exact>
          <AllQuotes />
        </Route>
        <Route path="/quotes/:quoteId">
          <QuoteDetail />
        </Route>
        <Route path="/new-quote">
          <NewQuote />
        </Route>
        <Route path="*">
          <NotFound />
        </Route>
      </Switch>
    </Layout>
  );
}

v6

function App() {
  return (
    <Layout>
      <Routes>
        <Route path="/" element={<Navigate replace to="/quotes" />} /> // Redirect
        <Route path="/quotes" element={<AllQuotes />} />
        <Route path="/quotes/:quoteId" element={<QuoteDetail />} />
        <Route path="/new-quote" element={<NewQuote />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </Layout>
  );
}
  • 전체 화면을 바꿔주는 Switch 태그가 Route 태그로 대체되었습니다.
  • Route의 element 태그 추가되었습니다.
  • Redirect가 사라지고 Route 태그와 Navigate 태그의 혼합형으로 대체되었습니다.

NavLink activeClassName

v5

const MainNavigation = () => {
  return (
    <ul>
      <li>
        <NavLink activeClassName={classes.active} to="/">
          All Quote
        </NavLink>
      </li>
      <li>
        <NavLink activeClassName={classes.active} to="/new-quote">
          Add a Quote
        </NavLink>
      </li>
    </ul>
  );
};

v6

const MainNavigation = () => {
  return (
    <ul>
      <li>
        <NavLink
          className={navData => (navData.isActive ? classes.active : '')}
          to="/"
        >
          All Quote
        </NavLink>
      </li>
      <li>
        <NavLink
          className={navData => (navData.isActive ? classes.active : '')}
          to="/new-quote"
        >
          Add a Quote
        </NavLink>
      </li>
    </ul>
  );
};
  • NavLink는 그대로이나, activeClassName props가 없어졌습니다.

useHistory → useNavigate

v5

import { useHistory } from 'react-router-dom';

const NewQuote = () => {
  const history = useHistory();

  useEffect(() => {
    if (status === 'completed') {
      history.push('/quotes');
    }
  }, [status, history]);

  // ...
};

v6

import { useNavigate } from 'react-router-dom';

const NewQuote = () => {
  const { sendRequest, status } = useHttp(addQuote);
  const navigate = useNavigate();

  useEffect(() => {
    if (status === 'completed') {
      navigate('/quotes');
    }
  }, [status, navigate]);

  // ...
};
  • 페이지 이동 시, 사용하던 useHistory가 useNavigate로 대체되었습니다.

중첩 Route

v5

import { Fragment, useEffect } from 'react';
import { useParams, Link, Route, useRouteMatch } from 'react-router-dom';

const QuoteDetail = () => {
  const match = useRouteMatch();

  return (
    <Fragment>
      <HighlightedQuote text={loadedQuotes.text} author={loadedQuotes.author} />
      <Route path={match.path} exact>
        <div className="centered">
          <Link className="btn--flat" to={`${match.url}/comments`}>
            Load Comments
          </Link>
        </div>
      </Route>

      <Route path={`${match.path}/comments`}>
        <Comments />
      </Route>
    </Fragment>
  );
};

// app.js
<Route path="/quotes/:quoteId" element={<QuoteDetail />} />;

v6

import { Fragment, useEffect } from 'react';
import { useParams, Outlet } from 'react-router-dom';

const QuoteDetail = () => {
  return (
    <Fragment>
      <HighlightedQuote text={loadedQuotes.text} author={loadedQuotes.author} />
      <Outlet />
    </Fragment>
  );
};

// app.js
import { Route, Routes, Navigate, Link } from 'react-router-dom';
function App() {
  return (
    <Layout>
      <Routes>
        <Route path="/quotes/:quoteId" element={<QuoteDetail />}>
          <Route
            path=""
            element={
              <div className="centered">
                <Link className="btn--flat" to={`comments`}>
                  Load Comments
                </Link>
              </div>
            }
          />
          <Route path={`comments`} element={<Comments />} />
        </Route>
      </Routes>
    </Layout>
  );
}

export default App;
  • useRouteMatch가 사라지고 상대경로를 사용할 수 있게 되었습니다.

Prompt

v5

import { Prompt } from 'react-router-dom';

const QuoteForm = props => {
  return (
    <Fragment>
      <Prompt
        when={isEntering}
        message={location =>
          'Are you sure you want to lewave? All your entered data will be lost!'
        }
      />
    </Fragment>
  );
};
  • Prompt가 사라졌습니다.

이렇게 마이그레이션 한 내용들을 정리했습니다. 물론 더 많은 변경사항과 아직 알지 못하는 기능들이 있을텐데 그건 추후에 필요할 때 스터디하도록 하겠습니다.