본문 바로가기
  • soldonii's devlog
Javascript 공부/React

리액트 라우터(React Router)로 컴포넌트에 프로퍼티 전달하기

by soldonii 2019. 12. 15.

*Udemy의 "Complete React Developer in 2020" 강의에서 학습한 내용을 정리한 포스팅입니다.

*자바스크립트와 리액트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. Router를 통해 각 컴포넌트에 전달되는 주요 프로퍼티

import React from 'react';
import { Route, Switch } from 'react-router-dom';

// import HomePage from './pages/homepages/homepage.component';
import './App.css';

const HomePage = (props) => {
  console.log(props); // 확인해보자.
  return (
    <div>
      <h1>HOME PAGE</h1>
    </div>
  )
}

const TopicsList = () => {
  return (
    <div>
      <h1>TOPICS LIST PAGE</h1>
    </div>
  )
}

const TopicDetail = () => {
  return (
    <div>
      <h1>TOPIC DETAIL PAGE</h1>
    </div>
  )
}

function App() {
  return (
    <div>
      <Route exact path="/" component={HomePage}/>
      <Route exact path="/topics" component={TopicsList}/>
      <Route path="/topics/:topicId" component={TopicDetail}/>
    </div>
  )
}

export default App;

첫번째 <Route>는 HomePage 컴포넌트를 렌더링하도록 되어있고, HomePage 컴포넌트는 props를 전달인자로 받아 console.log하고 있다. 이러한 경우 컴포넌트 내부에 props에는 어떠한 객체가 들어올까? props 객체에 들어오는 값들 중 주요한 것으로는 3개가 있다. history, location, match이다.

history: {length: 4, action: "POP", location: {…}, createHref: ƒ, push: ƒ, …}
location: {pathname: "/", search: "", hash: "", state: undefined}
match: {path: "/", url: "/", isExact: true, params: {…}}

 

# match 객체

match 객체 내의 주요 프로퍼티들은 아래와 같다.

- url : 렌더링되는 컴포넌트의 url을 나타낸다. 주의할 점은, 만약 Route에서 exact를 입력하지 않은 경우에는 localhost:3000/blah/blah와 같은 주소도 /를 포함하고 있으므로 렌더링 된다고 했다. 하지만 이 url에 존재하는 값은 /blah/blah가 아니라 최초 path로 설정한 "/"이다.

- path: Route 컴포넌트에 프로퍼티로 넘겨준 path의 값이 그대로 들어온다.

- isExact : path로 넘겨준 url 주소와 현재 화면의 주소가 정확히 일치할 경우 true, 아니면 false이다.

function App() {
  return (
    <div>
      <Route path="/" component={HomePage}/>
      <Route exact path="/topics" component={TopicsList}/>
      <Route path="/topics/:topicId" component={TopicDetail}/>
    </div>
  )
}

위와 같은 코드에서 localhost:3000/topics 주소에 접속했다고 해보자. 이 경우 HomePage 컴포넌트와 TopicsList 컴포넌트 모두 렌더링된다. 하지만 HomePage 컴포넌트에서 전달받은 props.match.isExact는 false, TopicsList 컴포넌트에서 전달받은 props.match.isExact는 true이다.

HomePage 컴포넌트는 접속한 주소에 "/"가 포함되어서 렌더링되기는 했으나, 접속한 주소와 path가 정확히 일치하지는 않기 때문에 false이다. 반면 TopicsList는 접속한 주소와 path가 정확히 일치하므로 true이다.

- params : url parameter가 객체의 형태로 들어가 있다. 예를 들어 localhost:3000/topics/13 이라는 주소에 접속할 경우, TopicDetail 컴포넌트에서 params에는 {topicId: 13} 객체가 들어오게 된다. 따라서 이 값이 필요한 경우에는 TopicDetail 컴포넌트 내부에서 props.match.params.topicId에 접근하면 현재 토픽의 ID인 13을 얻을 수 있다.

 

# history 객체

리액트에서 페이지 간 이동하는 방법은 크게 두가지가 있다.

 

1. react-router-dom의 Link 컴포넌트 이용하기

import React from 'react';
import { Route, Link } from 'react-router-dom';
import './App.css';

const HomePage = (props) => {
  // console.log(props);
  return (
    <div>
      <Link to='/topics'>Topics</Link>
      <h1>HOME PAGE</h1>
    </div>
  )
}

위처럼 Link 컴포넌트 또한 import한 후, Link 컴포넌트의 to 프로퍼티에 원하는 url 주소 값을 넣으면 마치 HTML의 a tag가 생성된 것 같은 효과를 주며, 이를 클릭하면 localhost:3000/topics 주소로 이동하게 된다.

 

2. history props를 이용하기

import React from 'react';
import { Route } from 'react-router-dom';
import './App.css';

const HomePage = (props) => {
  return (
    <div>
      <button onClick={() => props.history.push('/topics')}>Topic</button>
      <h1>HOME PAGE</h1>
    </div>
  )
}

HomePage 컴포넌트 내부에서 history 객체에 접근할 수 있다. 여기서 push 메소드를 이용해서 props.history.push('/topics')라고 할 경우, 해당 주소로 이동할 수 있게 된다. Link 컴포넌트와 같은 역할이지만 history 객체를 이용할 경우 더 동적으로 제어할 수 있다. 왜냐하면 단순히 a tag를 생성하는 Link와 달리, 이 방식은 함수를 이용하는 방식이기 때문에, 특정 조건이 충족됐을 때 이동하도록 하는 등 자바스크립트를 이용해 더 동적으로 제어가 가능하기 때문이다.

 

function App() {
  return (
    <div>
      <Route path="/" component={HomePage}/>
      <Route exact path="/topics" component={TopicsList}/>
      <Route path="/topics/:topicId" component={TopicDetail}/>
    </div>
  )
}

위와 같은 코드에서 localhost:3000/aer/123asgd/123ji0a 와 같은 주소에 접속했다고 가정해보자. DOM에 렌더링되는 것은 HomePage 컴포넌트만 렌더링 될 것이다. 그리고 이 HomePage 컴포넌트 내부에서 props.location.pathname 에 접근하면 "localhost:3000/aer/123asgd/123ji0a" 이 값을 얻을 수 있다. 즉 실제 현재의 url이 값으로 들어온다.

 

2. Router를 이용하여 동적 라우팅 구현하기

위에서 살펴본 3개의 프로퍼티를 활용하면 라우팅을 동적으로 구현할 수 있다.

const TopicsList = (props) => {
  return (
    <div>
      <h1>TOPICS LIST PAGE</h1>
      <Link to={`${props.match.url}/13`}>TO TOPIC 13</Link>
      <Link to={`${props.match.url}/17`}>TO TOPIC 17</Link>
      <Link to={`${props.match.url}/21`}>TO TOPIC 21</Link>
    </div>
  )
}

function App() {
  return (
    <div>
      <Route exact path="/" component={HomePage}/>
      <Route exact path="/topics" component={TopicsList}/>
      <Route path="/topics/:topicId" component={TopicDetail}/>
    </div>
  )
}

위 코드를 보면 TopicsList 내부에서 다른 주소로 이동할 수 있는 3개의 Link를 생성했다. 생성한 방식을 살펴보면, 단순히 특정 주소에 숫자를 붙여 이동하게 한 것이 아니라, props.match.url 값을 이용한 후 숫자를 더하고 있다.

정적인 str 주소가 아니라 저렇게 값을 이용하게 될 경우, 만약 TopicsList의 주소가 단순히 localhost:3000/topics가 아니라, localhost:3000/adf/12/asdfzcxv/aseraweg/ 와 같은 이상한 주소라고 할 지라도, props.match.url은 "localhost:3000/adf/12/asdfzcxv/aseraweg/"가 들어있으므로 여기서부터 숫자를 뒤에 덧붙여 이동이 가능한 점이다.

 

이를 잘 활용하면 nested route 구조를 동적으로 생성할 수 있다.

댓글