React Router

protect-me·2021년 9월 15일
0

⚛️ 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 ComponentwithRouter 활용
// 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개의 댓글