React Router

如何使用第三方库 react-router 实现复杂页面切换以及动态页面链接

React

Router 路由库

npm install react-router-dom

BrowserRouter

<BrowserRouter>作为 context provider, 其中的 children 可利用路由.

import React from "react"
import ReactDOM from "react-dom"
import { BrowserRouter } from "react-router-dom"

import App from "./App"

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
)
  • 跳转链接, to为目标链接, DOM 中渲染为 <a>
  • 默认情况下 path以传入到为起始, exact 则完全匹配
  • component传入无法接收 props, 传入children则可以传入 props
  • Link在哪里都可以 只是跳转链接
  • Switch可以相像成switch流程控制, 即根据当前的 path 渲染相对应的组件.
  • 通常写在一个单独的Navigator.jsx文件.

Navigator.jsx

import { Link, Switch, Route } from "react-router-dom"
import Home from "./Home"
import About from "./About"

const Navigator = () => {
  return (
    <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/about">
        <About />
      </Route>
    </Switch>
  )
}

App.jsx

const App = () => {
  return (
    <div>
      {/* 共享的组件 即每个路径都渲染 一般为导航栏组件 */}
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>

      {/* 路由条件渲染组件  */}
      <Navigator />
    </div>
  )
}

useParams

动态路由 分三步

  1. Route中配置动态路由存储的变量, 之后用useParams提取
  2. 动态生成Link
  3. 详情页面 使用 useParams提取路由的变量

Navigator.jsx

import { Link, Switch, Route } from "react-router-dom"

const Navigator = () => {
  return (
    <Switch>
      <Route exact path="/">
        <Home />
      </Route>
      <Route exact path="/subjects">
        <SubjectList />
      </Route>
      {/* 将路由的链接存储为subjectId */}
      <Route path="/subjects/:subjectId">
        <SubjectDetail />
      </Route>
    </Switch>
  )
}

SubjectList.jsx

const SubjectList = () => {
  const [subject, setSubject] = useState([])

  useEffect(() => {
    // API请求获取数据
  }, [])

  return (
    <div>
      <h1>All Subjects</h1>

      {/* 动态生成 Link */}
      {subject.map(s => (
        <Link to={`/subjects/${s.id}`}>{s.title}</Link>
      ))}
    </div>
  )
}

SubjectDetail.jsx

import { useParams } from "react-router-dom"

const SubjectDetail = () => {
  const param = useParams()
  const subjectId = param.subjectId
  // const {subjectId} = useParams 或者用Object Destruction

  useEffect(() => {
    // 根据id请求该Subject的详细信息
  })

  return <div>{/* UI */}</div>
}

export default SubjectDetail

useHistory

动态跳转. 例如 longin 登录后自动跳转. 需要在函数中处理更改链接.

import { useHistory } from "react-router-dom"

const Authentication = () => {
  const history = useHistory()

  const handleLogin = () => {
    // 账户验证...
    history.push("/") // 当前路径更改为 / 主页面
  }

  return (
    <form>
      <input placeholder="User name" />
      <input placeholde="Password" />
      <button onClick={handleLogin}>Log In</button>
    </form>
  )
}

useLocation

获取当前 path 的信息如下

  • pathname即当前的路径名, 如果需要判断当前路径名
  • search即路径中的Query String, ?之后的. 通常用于前端的 filter 或者排序展示特定的数据.
{
  "pathname": "/subjects",
  "search": "?sort=date&page=1",
  "hash": "",
  "state": null,
  "key": "qd3dcd5"
}
import { useLocation } from "react-router-dom"

const SubjectList = () => {
  const location = useLocation()

  return (
    <div>
      <h1>All Subjects</h1>
    </div>
  )
}

Redirect

登录认证 自动跳转

对于每次/private路由, 如果 isLoggedIn true, 则渲染 <Private /> 否则则自动跳转到 /login

import { Link, Switch, Route, Redirect } from "react-router-dom"

const App = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false)

  return (
    <div>
      <Link to="/">Home</Link>
      <Link to="/private">Private</Link>

      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route exact path="/private">
          {isLoggedIn ? <Private /> : <Redirect to="/login" />}
        </Route>
        <Route exact path="/login">
          <Login />
        </Route>
      </Switch>
    </div>
  )
}

export default App