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>
)
}
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>
)
}
query string
: 선택적 요소http://localhost:3000/about?name=hell
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>
)
}
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>
)
}
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'
// 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>
)
}
// 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>
)
}
// 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>
}
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>
})
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