초보 개발자의 성장 일기

리액트와 라우터의 관계 본문

Development/React JS

리액트와 라우터의 관계

YUNA 2023. 11. 22. 12:00

SPA

SPA(Single Page Application)은 하나의 페이지 요청으로 전체 웹앱을 사용하는 방식으로 유저는 웹페이지를 사용하며 모바일 앱 같은 경험을 느낀다. 리액트는 SPA 방식이다. React Router를 통한 SPA 내 화면 전환 및 주소 값 변경은 서버가 아니라 클라이언트 측에서 일어나기 때문에 Client-Side Routing이라고 한다.

  • Client-side routing 기술을 활용, 페이지 진입 시 리로드없이 라우팅한다.
  • AJAX 기술을 활용, 페이지 이동 시 서버에 데이터만 요청하여 자바스크립트로 페이지를 만든다.
  • MPA와 다르게, 여러 페이지를 하나의 앱의 구성요소로 보고 여러 페이지 간의 스타일, 컴포넌트를 재활용하는 방향으로 구현한다.
  • 자바스크립트만을 활용해 전체 페이지를 만들기에, 첫 요청 시 빈 페이지를 받게 된다.

라우팅

라우팅은 사용자가 웹사이트의 다른 페이지로 이동하는 프로세스이다. 

 

  • 서버에서 페이지를 만들 필요가 없으므로 CDN에 캐싱이 가능하다.
  • 매번 페이지 요청을 할 필요가 없어 네트워크 요청이 줄어든다.
  • 마찬가지로 데이터 요청 등을 캐싱하여 재사용하는 등 제약 조건이 줄어든다.
  • 웹사이트를 개별 페이지보다는 하나의 앱으로 보는 설계로 고도의 소프트웨어 설계와 패턴을 적용할 수 있다.

CDN

콘텐츠 전송 네트워크는 데이터 사용량이 많은 애플리케이션의 웹 페이지 로드 속도를 높이는 상호 연결된 서버 네트워크이다. 사용자가 웹 사이트를 방문할 때 해당 웹 사이트 서버의 데이터는 사용자의 컴퓨터에 도달하기 위해 인터넷을 통해 이동해야 하는데,사용자가 해당 서버에서 멀리 떨어져 있는 경우 동영상 또는 웹 사이트 이미지와 같은 대용량 파일을 로드하는 데 시간이 오래 걸린다. 대신 웹 사이트 콘텐츠는 지리적으로 사용자와 가까운 CDN 서버에 저장되며 컴퓨터에 빨리 도달한다.

 

 

그렇다면 SPA의 기술적 어려움은 어떤점이 있을까?

  • MPA방식 보다는 Search Engine Optimization에 불리하다.
  • 하나의 자바스크립트 앱이 지속하므로, 메모리 관리와 성능, 데이터 활용 등이 중요하다.
  • 여러 페이지를 전송받는 것 보다, 하나의 거대한 자바스크립트 앱을 전송받아야 하므로 코드가 많아질수록 로드 속도가 느리다.

SEO

검색 엔진 최적화는 구글과 네이버처럼 웹사이트가 검색 결과에 더 잘 보이도록 최적화하는 것이다.

 

 

SPA와 라우팅은 어떤 관련이 있을까?

유저가 다른 페이지로 이동했을 때 리로딩이 없어야 한다. 즉 SPA 라우팅은 리로딩을 없애고 페이지 전환을 구현하는 라이브러리이다.

 

  • 주로 History API 혹은 URL Hash를 이용해 페이지 리로드 없는 페이지 전환을 구현한다.
  • history, location 등 HTML5 API를 활용한다.
  • visibilitychange, popstate, beforeunload 등 window event를 활용하여 페이지 전환 등의 이벤트 시 핸들러를 등록한다.
  • react-router, reach-router 등의 라이브러리를 활용하면, 라우팅 관련 기능을 쉽게 사용할 수 있음

 

MPA

MPA(Multi Page Application)은 서버에 미리 여러 페이지를 두고, 유저가 네비게이션 시 요청에 적합한 페이지를 전달한다. 미리 서버에서 전체 페이지를 빌드해 브라우저로 전송된다. 서버에 라우팅을 처리하는 기능이 있고, 서버에서 여러 페이지를 관리한다. 페이지 요청마다 모든 리소스를 다시 받아와서 페이지 간 데이터를 재활용하기 힘들다.

 

react-router

  • Declarative routing for React. 
  • React의 JSX(<Link to=' /login'>를 이용하거나, History API를 사용하여 라우팅을 구현한다.
  • 웹에서는 react-router-dom을 사용한다. (앱: react-router-native)
  • 적용 시, 서버의 모든 path에서 같은 앱을 서빙하도록 해야 한다.

 

react-router에는 어떤 기능이 있을까?

  • React 컴포넌트를 특정 path와 연결하면, 해당하는 path로 진입 시 컴포넌트를 렌더링하게 한다. (<Ruter path='/login'> <login page/>)
  • query, path variable 등 URL parameter를 얻어 활용한다. (/login?email=abc@abc.com)
  • 조건에 맞지 않을 경우 redirect 한다.<redirect to='register' />
  • 페이지 이동 시, 이벤트 핸들러를 등록한다. (history.listen(cb))
  • /posts/my-post-1 등의 nested route를 구현한다. 

 

react-router의 사용 방법

  • <BrowserRouter>로 감싸 Router Context를 제공해야 한다.
  • Route로 path를 정의하고, 그 안에 렌더링하고자 하는 컴포넌트를 넣는다.
  • Link로 특정 페이지로 이동 시, 리로드 없이 페이지가 이동한다.
  • 매칭되는 라우터를 전부 렌더링 하지 않도록 Switch를 이용해 매칭되는 라우트 하나를 렌더링하게 한다.
import { BrowserRouter, Route, Switch } from 'react-router-dom'

export function App() {
    return (
        <BrowserRouter>
            <Switch>
                <Route path="/about"><AboutPage /></Route>
                <Route path="/contact"><ContactPage /></Route>
                <Route path="/"><HomePage /></Route>
            </Switch>
        </BrowserRouter>
    )
}

HomePage를 맨 위에 넣게 되면'/'가 들어간 페이지가 전부 HomePage으로 이동된다. 맨 아래에 넣거나 exact를 활용한다.

 

import { NavLink } from 'react-router-dom'

function HomePage() {
    return (
        <div>
            <nav>
                <NavLink to="/">Home</NavLink>
                <NavLink to="/about">About</NavLink>
                <NavLink to="/contact">Contact</NavLink>
            </nav>
            <div>Home 페이지</div>
        </div>
    )
}

NavLink는 매칭되는 링크가 자기 자신일 경우 강조가 처리되는 속성이 있다.

 

react-router 컴포넌트

BrowserRouter

브라우저 환경에서 라우팅 기능을 이용할 수 있도록 제공하는 컴포넌트이다.

 

  • HTML5의 History API를 사용하여, UI와 URL의 싱크를 맞추는 역할이다.
  • 모든 URL에 대해 동작하게 하기 위해서는 서버 설정이 필요하다.
  • 모든 path 앞의 basename을 지정할 수 있음. ex) basename="/ko"
  • forceRefresh로, 페이지 이동 시 리프레시할 것인지 지정할 수 있다.

 

Swich

여러 Route 중 위에서부터 매치되는 하나를 선택하여 렌더링하는 컴포넌트이다.

  • 매칭되는 Route가 없으면 아무것도 보여주지 않는다.
  • fallback용으로 404 Not Found Page를 추가한다.
  • path="/"의 경우 모든 path에 매칭되므로 exact 키워드를 추가하거나 가장 아래로 내린다.

 

Route

path와 컴포넌트를 매칭할 수 있게 하는 컴포넌트이다.

  • 매칭되는 컴포넌트는 children으로 넣어주거나 component prop으로 넘긴다.
  • exact 키워드로 정확하게 매칭하는 path를 설정한다.
  • Route로 렌더링 되는 최상위 컴포넌트는 match, location, history를 prop으로 받는다.
  • render prop으로, 매칭되었을 때 실제 어떤 컴포넌트를 렌더링할지 통제한다.

 

Redirect

Link와 비슷하나, 렌더링되면 to prop으로 지정한 path로 이동하는 컴포넌트이다.

  • Switch 안에서 쓰일 경우, from, to를 받아 이동하게 만든다. (from="/" to="/login")

 

Link, NavLink

  • to prop을 특정 URL로 받아, 클릭 시 네비게이션 한다.
  • anchor tag를 래핑한다.
  • NavLink의 경우, 매칭 시 어떤 스타일을 가질지 등의 추가 기능이 있다.
  • to에 location object나 함수를 받을 수 있다.

 

react-router 객체에 접근 가능한 Hook

useHistory, useLocation, useParams, useRouteMatch

  • 최상위 컴포넌트가 아니더라도, hook으로 react-router 관련 객체에 접근할 수 있다.
  • history, location, params, match 객체에 접근한다.

 

react-router로  페이지 구성하기

컴포넌트

 

공통 페이지

export default function PageLayout({ header, children }) {
	return (
        <Layout>
            <Navigation />
            
            <header>
                <h2>{header}</h2>	
            </header>
            
            <main>{children}</main>
        </Layout>
    );
}

 

공통 페이지 네비게이션

function Navigation() {
    return (
        <Nav>
            <NavLink to="/">Home</NavLink>
            <NavLink to="/about">About</NavLink>
            <NavLink to="/contact">Contact</NavLink>
        </Nav>
    );
}

 

개별 페이지 컴포넌트

function HomePage() {
    return (
    	<PageLayout header="Home Page">홈페이지에 오신 것을 환영합니다.</PageLayout>
    );
}

 

라우터 연결

function App() {
    return (
        <BrowserRouter>
            <Switch>
                <Route exact path="/">
                	<HomePage />
                </Route>
                <Route path="/about">
                	<AboutPage />
                </Route>
                <Route path="/contact">
                	<ContactPage />
                </Route>
            </Switch>
        </BrowserRouter>
    );
}

 

Private Route

패스로 접근시 아무나 통과하지 못하게 처리를 하는 라우터이다. 특정 조건이 충족되지 않았을 때 다른 페이지로 Redirect 하도록 하는 기능이며 유저의 상세 페이지, 개인정보 변경 페이지 등을 만들 때 사용된다.

 

declarative(선언)

function PrivateRoute({ component: Component, ...props }) {
    return <Route {...props} render={props => {
        const isLoggedIn = !!getUserInfo()
        if (!isLoggedIn) {
            return <Redirect to="/login" />
        }
        return <Component {...props} />
    }}
}

!!는 데이터가 유효한지 불리언으로 바꿔주는 표현식

 

imperative(명령)

function usePrivateRoute(validateFunc) {
    const history = useHistory()
    
    useEffect(() => {
        if (!validateFunc()) {
        	history.push("/login")
        }
    }, [])
}

 

query string

URL의 query string 정보를 활용해 앱을 구성하고 URLSearchParams API를 활용한다.

function ContactPage() {
    const location = useLocation();
    const searchParams = 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>
    );
}

#엘리스트랙 #엘리스트랙후기 #리액트네이티브강좌 #온라인코딩부트캠프 #온라인코딩학원 #프론트엔드학원 #개발자국비지원 #개발자부트캠프 #국비지원부트캠프 #프론트엔드국비지원 #React #Styledcomponent #React Router Dom #Redux #Typescript #Javascript

'Development > React JS' 카테고리의 다른 글

리액트 상태관리  (0) 2023.11.27
비동기 통신과 Promise  (0) 2023.11.24
리액트 앱에서의 스타일링 방법  (1) 2023.11.20
리액트 기초 (2) - Hooks  (0) 2023.11.17
리액트 기초 (1) - props, state, 이벤트 처리  (0) 2023.11.15