老牌的应用获取新页面需要发送HTTP请求,由服务器返回HTML
在单页面应用(single page apps)中,我们实际总是在同一页面, 如果发送HTTP GET请求,也只是为了获取JSON数据
每个视图(view)最好都有自己的地址,这样方便用户收藏书签,浏览器返回到上一页面也得以实现
安装React-router-dom
npm install react-router-dom
一个使用React-router的示例
import React from 'react'import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'const Home = () => (<div>{' '}<h2>TKTL notes app</h2>{' '}</div>)const Notes = () => (<div>{' '}<h2>Notes</h2>{' '}</div>)const Users = () => (<div>{' '}<h2>Users</h2>{' '}</div>)const App = () => {const padding = {padding: 5,}return (<Router><div><Link style={padding} to="/">home</Link><Link style={padding} to="/notes">notes</Link><Link style={padding} to="/users">users</Link></div><Switch><Route path="/notes"><Notes /></Route><Route path="/users"><Users /></Route><Route path="/"><Home /></Route></Switch><div><i>Note app, Department of Computer Science 2021</i></div></Router>)}export default App
路由,或者基于url的条件渲染,通过将组件放在Router组件中来实现
Router实际上是导入BrowserRouter后的别称
import { BrowserRouter as Router,Switch, Route, Link } from 'react-router-dom'
BrowserRouter is a Router that uses the HTML5 history API (pushState, replaceState and the popState event) to keep your UI in sync with the URL.
在Router内部,我们通过Link组件,修改地址栏的url
<Link to="/notes">notes</Link>
根据地址栏URL来渲染对应的组件,是在Route组件中实现的
<Route path="/notes"><Notes /></Route>
将所有基于url渲染的组件都放在Switch组件里, 即这些组件的视图区域都在Switch里
<Switch><Route path="/notes"><Notes /></Route><Route path="/users"><Users /></Route><Route path="/"><Home /></Route></Switch>
注意,在Switch内部的顺序很重要,如果将path=”/“放在第一个,所有以’/‘开头的url都能与之匹配,导致其他所有组件都得不到渲染。
同理,如果url A包含了B, 且A比B长,那么A要放前面,否则永远匹配不到A
<Switch><Route path={'/anecdotes/:id'}><Anecdote anecdote={anecdote} /></Route><Route path={'/anecdotes'}><AnecdoteList anecdotes={anecdotes} /></Route></Switch>
Parameterized route
每条li都是可以点击的Link, 当点击时,修改地址栏的url
const Notes = ({notes}) => (<div><h2>Notes</h2><ul>{notes.map(note =><li key={note.id}><Link to={`/notes/${note.id}`}>{note.content}</Link></li>)}</ul></div>)
Route通过**:id**传递参数(express style)
<Switch><Route path="/notes/:id"><Note notes={notes} /></Route><Route path="/notes"><Notes notes={notes} /></Route><Route path="/"><Home /></Route></Switch>
通过**useParams()**获取url的参数
import {// ...useParams} from "react-router-dom"const Note = ({ notes }) => {const id = useParams().idconst note = notes.find(n => n.id === Number(id))return (<div><h2>{note.content}</h2><div>{note.user}</div><div><strong>{note.important ? 'important' : ''}</strong></div></div>)}
useHistory
通过useHistory, 组件可以访问history对象,通过向history对象push一个地址,将url修改为对应的地址并渲染对应的组件。
import {// ...useHistory} from 'react-router-dom'const Login = (props) => {const history = useHistory()const onSubmit = (event) => {event.preventDefault()props.onLogin('mluukkai')history.push('/')}return (<div><h2>login</h2><form onSubmit={onSubmit}><div>username: <input /></div><div>password: <input type='password' /></div><button type="submit">login</button></form></div>)}
Redirect
如果user不存在,则不渲染Users组件,而是重定向到/login, 即修改地址为/login并渲染
<Route path="/users">{user ? <Users /> : <Redirect to="/login" />}</Route>
Parameterized route revisited
使用useRouteMatch获取匹配的url信息
将Router移到App外面
ReactDOM.render(<Router><App /></Router>,document.getElementById('root'))
在App组件内部使用useRouteMatch
import {// ...useRouteMatch} from "react-router-dom"const App = () => {// ...const match = useRouteMatch('/notes/:id')const note = match? notes.find(note => note.id === Number(match.params.id)): nullreturn (<div><div><Link style={padding} to="/">home</Link>// ...</div><Switch><Route path="/notes/:id"><Note note={note} /></Route>// ...</Switch></div>)}
每次浏览器url更改时,都会执行如下代码
const match = useRouteMatch('/notes/:id')
当匹配到url时就能获取到对应的信息
参考资料: React-router hooks
