리액트 라우터 그리고 라우터 훅

김종현·2023년 5월 17일
0

설치 : React-Router-Dom 라이브러리 사용.

npm install react react-router react-router-dom

페이지 레이아웃을 만들면 서로 다른 여러 페이지가 있어도 공통된 부분을 묶어 처리하는 공통화가 가능.

url에서 패스변수, 쿼리스트링을 얻고 link는 anchor tag를 래핑.

Router Context 안에서만 BrowserRouter가 동작.

Route안에 Route가 들어갈 경우 nested route로 구현하며 history.listen으로 이벤트 핸들러를 등록한다.

예시

import React, { useRef } from 'react';
import {BrowserRouter as Router, Routes, Route, Link} from 'react-router-dom'

export default function ReactRouting() {
  const userID = useRef('ref값 넘기기:홈')
  const userID2 = useRef('ref값 넘기기:로그인')
  return (
    <Router>
      <Routes>
		<Route path="/" element={ <HomePage userID={userID.current}/> }/>
		<Route path="/login" element={ <LoginForm userID2={userID.current}/> }/>
          //잘못된 경로에 의한 Redirect는 아래와 같이.
          // ~/, ~/login 경로가 아니면 /notfound로 이동.
		<Route path="*" element={ <NotFound />}/>
      </Routes>
    </Router>
  );
}

//각 라우터에 해당하는 컴포넌트
function HomePage({userID}) {
  return (
    <div>
      <h2>Home Page</h2>
      <div>
        <Link to="/login">Login</Link>
    	<span>{userId}</span>
      </div>
    </div>
  );
}

function LoginPage({userID2}) {
  return (
    <div>
      <h2>Login Page</h2>
      <LoginForm />
      <div>
    	<Link to="/">Back to home</Link>
    	<span>{userId2}</span>
	</div>
    </div>
  );
}

BrowserRouter 컴포넌트를 사용시 각 내부 component 안에서 router context를 활용할 수 있음.(리액트 라우터 관련 컴포넌트 사용 가능)

Route
Route로 렌더링 되는 '최상위 컴포넌트'는 match, location, navigate를 prop으로 받음
-render prop으로 매칭시 실제 어떤 컴포넌트를 렌더링할지 콜백으로 통제

<Route render={ () => {} }>

매개변수를 받아 이것이 10보다 크면 A, 작으면 B 렌더링 이런식의 조건 걸 수 있음
-route에서 불러오는 컴포넌트에 prop을 넘겨줄때는 route 컴포넌트가 아니라 해당 컴포넌트 내에 직접 넣어줌.

<Route path='/' element={<Home id={idRef.current} />}

Link, NavLink
to prop을 특정 url로 받아 클릭 시 네비게이션.함
anchor tag를 래핑함
NavLink(주로 네비게이션 처리에 사용)의 경우 매칭 시 어떤 스타일을 가질지 정하는 추가 기능 존재.
to에 location obj나 함수를 받을 수 있음

ex) location ={hash : ~, pathname : ~, state : ~ }
<Link to={location}/>
<Link to='users'> To Users </Link>
=> <a> To Users </a>

라우터 훅

useNavigate

기존 useHistory는 사용 시 history 객체를 반환했지만, useNavigate는 navigate() 함수를 사용합니다. useNavigate를 통해 Link를 사용하지 않아도 버튼을 구현하여 다른 페이지로 이동이 가능

useNavigate(URL주소를 변경할 때 사용하는 Hook), useLocation, useParams, useRouteMatch
최상위 컴포넌트가 아니더라도 hook으로 react-router 관련 객체에 접근 가능. 각각 navigate, location, params, match 객체에 접근함.
-const location = useLocation() 이런식으로 객체 얻어와서 location.state와 같이 깔끔하게 사용.
-즉 path에 있는 정보에 접근하려면 이런 hook들 사용.

[React Route 응용]
1.Private Route - declarative
특정 조건만족시 접근 가능한 라우트. 미충족시 다른 페이지 라이다이렉트.
유저의 상세 페이지, 개인정보 변경 페이지 만들 때 사용

function PrivateRoute({ component: Component, ...props}){
return <Route {...props} render={props =>{
    // !!이거는 데이터가 valid한지 boolean으로 바꿔줌
   const isLoggedIn = !!getUserInfo()
   if(!isLoggedIn) {
      return <Redirect to='/login' />
   }
   return <Component {...props} />
   }}
}

2. imperative
finction usePrivateRoute(validateFunc) {
   const history = useHistory()

   useEffect( ()=>{
      if(!validateFunc()) {
// login으로 url 이동
         history.push('/login')
       }
   }, [])
}

[쿼리스트링 활용] 일종의 상태관리 방법이 될 수 있음
url의 쿼리 스트링 정보를 활용해 앱을 구성할 수 있음
URLSearchParams API를 활용.. 해당 컴포넌트로 가는 라우트에서 데이터 얻음.


function ContactPage(){
   const location = useLocation();
   const seachParams = new URLSearchParams(location.search);

   const email = searchParams.get('email');
   const address = searchParams.get('address');

   return(
      <PageLayout header='Contact Page'>
         <em>{email}</em>
         <br/>
         <strong>{address}</strong>
      </PageLayout>
   );
}

function App(){
   ...
      return(
//위에서 짠 컨택트 페이지로 라우팅
         <Link to='/contact?email=example@example.com@address=Seoul'>
            Contact
         </Link>
      );
> }

useLocation

useLocation Hook은 현재 URL의 정보를 가지는 location 객체를 반환.

const location = useLocation();
console.log(location)
=>
{pathname: '/user/1', search : '', hash : '', state: undefined}

location 객체는 대표적으로 key, pathname, search, state의 속성값을 가진다.
ex) https://study/courses?name=kim&year=2023
-pathname: 위의 예시에서 /courses처럼 endpoint를 의미.
-search: 위의 예시에서 ? 이후의 queryString 값.
-state: 이전 페이지로부터 전달받은 인자.

① 이때, location 객체의 search 속성값과 URLSearchParams 객체를 함께 사용하면 queryString의 key, value쌍을 쉽게 가져올 수 있음

URLSearchParams : URL의 쿼리 문자열을 대상으로 작업할 수 있는 유틸리티 메서드를 정의.
-URLSearchParams(location.search) : URLSearchParams 객체 인스턴스를 반환. 이경우 location의 search를 내놓음.

예시

---InfoCard.jsx
export default function InfoCard({ info }) {
  const name = info.name;
  const nav = useNavigate();

  const handleClick = () => {
    nav(`/detail?name=${info.name}&phone=${info.phone}&addr=${info.addr}`);
  };

  return <Card onClick={handleClick}>{name}</Card>;
}

---Detail.jsx

export default function Detail() {
  const location = useLocation();
  const search = new URLSearchParams(location.search);

  return (
        <div>
          <span>name:{search.get("name")}</span>
  
          <span>phone:{search.get("phone")}</span>

          <span>addr:{search.get("addr")}</span> 
        </div>
)

② 혹은 location 객체의 state를 활용하면 queryString을 사용하는 방식과 달리 URL에 정보를 담지 않고도 하위 컴포넌트로 데이터를 전달할 수 있음.

이전에는 pathname과 state가 설정된 location object를 history 객체에 push하여 state를 전달했으나 v6부턴 navigate를 사용해 state를 전달해야 함.

const nav = useNavigate();
nav("/example", { state: data});

위의 예시와 같이 navigate 함수의 두 번째 인자로 state에 data를 넣어 location obj를 전달해야함. 이 경우 location.state에 들어갈 값으로 data를 할당하여 /detail로 보내게 됨.

이후 DetailPage.jsx에서 location.state를 사용하기 위해 useLocation 훅을 이용해 location 객체를 만들어주고 location.state를 가져와 content 영역을 채우면 됨.

예시

---InfoCard.jsx
export default function InfoCard({ info }) {
  const name = info.name;
  const nav = useNavigate();
  const location = useLocation();

  const handleClick = () => {
    nav('/detail', {state : info})
  };

  return <Card onClick={handleClick}>{name}</Card>;
}

---Detail.jsx
export default function DetailPage() {
  const location = useLocation();
  const info = location.state;

  return (
        <div>
          <span>name:{info.name}</span>

          <span>phone:{info.phone}</span>

          <span>addr:{info.addr}</span>
        </div>
  );
}
profile
나는 나의 섬이다.

0개의 댓글