React Router

protect-me·2021년 9월 15일

⚛️ React

목록 보기
4/7
post-thumbnail

참고 https://slides.com/woongjae/react2021

React의 라우팅 이해하기

비교

  • 기존 방식
  • SPA | Single Page Application

SPA 라우팅 과정

  1. 브라우저에서 최초에 '/'경로로 요청을 하면
  2. React Web App을 내려줌
  3. 내려받은 React App에서 '/'경로에 맞는 컴포넌트를 보여줌
  4. ReactApp에서 다른 페이지로 이동하는 동작을 수행하면
  5. 새로운 경로에 맞는 컴포넌트를 보여줌

React는 작성, 렌더, 업데이트에 관여하는데,
route는 기본적으로 react의 범주를 넘어서는 작업
⇒ React Router Dom Library가 그 일을 대신함

$npm i react-router-dom
CRA에 기본 내장된 패키지도, 공식 패키지도 아님
가장 대표적인 라우팅 패키지임


기본 라우팅

// App.js
import { BrowserRouter, Route } from 'react-router-dom'
import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'
import './App.css'

function App() {
  return (
    <BrowserRouter>
      <Route path="/" exact component={Home}></Route>
      <Route path="/profile" component={Profile}></Route>
      <Route path="/about" component={About}></Route>
    </BrowserRouter>
  )
}

export default App
export default function Profile() {
  return (
    <div>
      <h2>Profile</h2>
    </div>
  )
}

동적 라우팅 (1)

  • params: 필수 요소
  • http://localhost:3000/profile/10
// App.js
(...)
<Route path="/profile" exact component={Profile}></Route>
<Route path="/profile/:id" component={Profile}></Route>
(...)
// profile.jsx
export default function Profile(props) {
  const id = props.match.params.id
  console.log(id, typeof id)
  return (
    <div>
      <h2>Profile</h2>
      {id && <p>id 는 {id} 입니다.</p>}
    </div>
  )
}

동적 라우팅 (2)

  • query string: 선택적 요소
  • http://localhost:3000/about?name=hell

basic

export default function About(props) {
  const searchParams = props.location.search
  console.log(searchParams)
  const obj = new URLSearchParams(searchParams)
  const name = obj.get('name')
  console.log(name)
  return (
    <div>
      <h2>About</h2>
      {name && <p>name은 {name}입니다.</p>}
    </div>
  )
}

query-string library

import queryString from 'query-string'

export default function About(props) {
  const searchParams = props.location.search
  console.log(searchParams)
  // const obj = new URLSearchParams(searchParams)
  // const name = obj.get('name')
  // console.log(name)
  const query = queryString.parse(searchParams)
  console.log(query)
  return (
    <div>
      <h2>About</h2>
      {query.name && <p>name은 {query.name}입니다.</p>}
    </div>
  )
}

Switch와 NotFound

  • 여러 Route 중 순서대로 먼저 맞는 하나만 보여줌
  • 로직에서 exact를 뺄 수 있게 해줌
  • 가장 마지막에 어느 path에도 맞지 않는 경우를 설정해서 Not Found 페이지를 만들 수 있음
// App.js
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'
import NotFound from './pages/NotFound.jsx'
import './App.css'

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/profile/:id" component={Profile}></Route>
        <Route path="/profile" component={Profile}></Route>
        <Route path="/about" component={About}></Route>
        <Route path="/" exact component={Home}></Route>
        <Route component={NotFound}></Route>
      </Switch>
    </BrowserRouter>
  )
}

export default App

<a></a> 태그를 통해 이동하면 React Application의 SPA 특성을 담은 페이지 이동이 아니라 서버에 새로운 요청을 일으킴. 즉, 새로고침이 일어남
⇒ <Link></Link> 컴포넌트를 활용

import { BrowserRouter, Route, Switch, Link } from 'react-router-dom' // Link import
import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'
import NotFound from './pages/NotFound.jsx'
import './App.css'

function App() {
  return (
    <BrowserRouter>
      <Link to="/">Home</Link>
      <Switch>
        <Route path="/profile/:id" component={Profile}></Route>
        <Route path="/profile" component={Profile}></Route>
        <Route path="/about" component={About}></Route>
        <Route path="/" exact component={Home}></Route>
        <Route component={NotFound}></Route>
      </Switch>
    </BrowserRouter>
  )
}

export default App
import { Link } from 'react-router-dom'

export default function Links() {
  return (
    <ul>
      <li>
        <Link to="/">Home</Link>
      </li>
      <li>
        <Link to="/profile">Profile</Link>
      </li>
      <li>
        <Link to="/profile/1">Profile/1</Link>
      </li>
      <li>
        <Link to="/about">About</Link>
      </li>
      <li>
        <Link to="/about?name=hell">About?name="hell</Link>
      </li>
    </ul>
  )
}

  • import {NavLink} from 'react-router-dom'
  • activeClassName, activeStyle 처럼 active 상태에 대한 스타일 지정이 가능
  • Route의 path 처럼 동작하기 때문에 exact가 있음
// NavLinks.js
import { NavLink } from 'react-router-dom'
const activeStyle = { color: 'green' }

export default function NavLinks() {
  return (
    <ul>
      <li>
        <NavLink to="/" exact activeStyle={activeStyle}>
          Home
        </NavLink>
      </li>
      <li>
        <NavLink to="/profile" exact activeStyle={activeStyle}>
          Profile
        </NavLink>
      </li>
      <li>
        <NavLink to="/profile/1" activeStyle={activeStyle}>
          Profile/1
        </NavLink>
      </li>
      <li>
        <NavLink
          to="/about"
          activeStyle={activeStyle}
          isActive={(match, location) => {
            console.log('match', match)
            console.log('location', location)

            return match !== null && location.search === ''
          }}
        >
          About
        </NavLink>
      </li>
      <li>
        <NavLink
          to="/about?name=hell"
          activeStyle={activeStyle}
          isActive={(match, location) => {
            console.log('location', location)
            return match !== null && location.search === '?name=hell'
          }}
        >
          About?name=hell
        </NavLink>
      </li>
    </ul>
  )
}

JS로 라우팅 이동

기본

// Login.jsx
export default function Login(props) {
  console.log('props', props)

  function login() {
    setTimeout(() => {
      props.history.push('/') // go, goback, push, replace...
    }, 1000)
  }

  return (
    <div>
      <h2>Login</h2>
      <button onClick={login}>로그인하기</button>
    </div>
  )
}

component 분리 (1) - 지양

  • 부모 컴포넌트에서 자식 컴포넌트로 직접 props를 넘겨주는 방식
// Login.jsx
import LoginButton from '../components/LoginButton'
export default function Login(props) {
  return (
    <div>
      <h2>Login</h2>
      <LoginButton {...props} />
    </div>
  )
}
// LoginButton.jsx
export default function LoginButton(props) {
  console.log('LoginButton Props', props)
  function login() {
    setTimeout(() => {
      props.history.push('/')
    }, 1000)
  }
  return <button onClick={login}>로그인하기</button>
}

component 분리 (2) - HOC

  • Higher Order Component인 withRouter 활용
// Login.jsx
import LoginButton from '../components/LoginButton'
export default function Login() {
  return (
    <div>
      <h2>Login</h2>
      <LoginButton />
    </div>
  )
}
// LoginButton.jsx
import { withRouter } from 'react-router-dom'

export default withRouter(function LoginButton(props) {
  console.log('LoginButton Props', props)
  function login() {
    setTimeout(() => {
      props.history.push('/')
    }, 1000)
  }
  return <button onClick={login}>로그인하기</button>
})

component 분리 (3) - Hook

  • hook을 통한 방법도 있음(차후 학습)

Redirect

import { Redirect} from 'react-router-dom

// App.js
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'
// import Links from './components/Links.jsx'
import NavLinks from './components/NavLinks.jsx'
import Login from './pages/Login'
import Home from './pages/Home'
import Profile from './pages/Profile'
import About from './pages/About'
import NotFound from './pages/NotFound.jsx'
import './App.css'

const isLogin = false // isLogin에 따라서 home으로 갈지 login으로 갈지 결정됨

function App() {
  return (
    <BrowserRouter>
      {/* <Link to="/">Home</Link> */}
      {/* <Links></Links> */}
      <NavLinks></NavLinks>
      <Switch>
        <Route
          path="/login"
          render={() => (isLogin ? <Redirect to="/" /> : <Login />)}
        ></Route>
        <Route path="/profile/:id" component={Profile}></Route>
        <Route path="/profile" component={Profile}></Route>
        <Route path="/about" component={About}></Route>
        <Route path="/" exact component={Home}></Route>
        <Route component={NotFound}></Route>
      </Switch>
    </BrowserRouter>
  )
}

export default App
profile
protect me from what i want

0개의 댓글