React 系列之基础三(路由篇)

React 系列之基础三

React 路由

React 路由帮组我们根据浏览器地址栏的 URL 将应用划分到不同的视图.

1. React-router

1. 快速开始

npm install --save react-router-dom

使用简单示例:

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

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 2020</i>
      </div>
    </Router>
  )
}
  • BrowserRouter 是一个 Router
    它使用 HTML5 的 history API(pushState, replaceState 和 popState 事件) 保持UI 与 URL 同步.

通常地址栏 URL 变化, 浏览器会加载一个新的页面. 然而, 借助 HTML history Api BrowserRouter, 我们可以使用浏览器 URL 在 react-application 中进行内部"路由". 因此这种方式, URL 变化, 页面的内容是通过 JavaScript 来替换的.

  • Link
    在路由内部, 定义 Link 组件, 用于修改地址栏 URL
  • Switch & Route
    基于浏览器 URL 渲染的组件是在组件 Route 下定义的
    并通过 Switch 保证要基于 url 渲染的 Route

2. 参数化路由 (useParams)

在 上面 Link 组件中, to 的值是固定的. 同样, 也可以设置参数化路由值.

	<Route path="/notes/:id">
        <Note notes={notes} />
      </Route>

在这个 Route 中, 通过 冒号 :id 标签参数来定义路由的 path. 下面是Note.js 定义, 里面通过 useParams 获取 url 参数:

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

const Note = ( { notes } ) => {
	// 通过 useParams 获取 url 的参数
	const id = useParams().id
  	const note = notes.find(n => n.id === Number(id))
  	return ... 
}

3. useHistory 使用

有了这个 函数, 组件就可以访问一个 history 对象. 历史记录对象可以用于编程化地修改浏览器的 url.
例如在 一个 Login 组件中:

import {
  // ...
  useHistory
} from 'react-router-dom'

const Login = (props) => {
  const history = useHistory()
  // 登录提交 处理函数
  const onSubmit = (event) => {
    event.preventDefault()
    // 当前登录的用户 mluukkai
    props.onLogin('mluukkai')
    // 修改浏览器 url
    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>
  )
}

4. 重定向 (redirect)

<Redirect to="xx" />

假设需求: 如果用户未登录, 跳转到登录页面, 如果已经登录则正常跳转

<Route path="/users" render={() => 
	user ? <Users /> : <Redirect to="/login" />
} />

5. 参数化路由的缺陷 (useRouteMatch)

在参数化路由中:

<Route path="/notes/:id">
        <Note notes={notes} />
      </Route>

Note 组件需要传递到 note 集合, 根据 useParams 给到的 id 查询出 需要显示的 note 实例.

一种方法是使用 react-router 的 useRouteMatch

  • 在定义应用路由部分的组件中不可能使用useRouteMatch-hook。 让我们把路由组件的使用从 App 中移除
  • 组件变成如下所示:
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))
    : null

  return (
    <div>
      <div>
        <Link style={padding} to="/">home</Link>
        // ...
      </div>

      <Switch>
        <Route path="/notes/:id">
          <Note note={note} />
        </Route>
        <Route path="/notes">
          <Notes notes={notes} />
        </Route>
         // ...
      </Switch>

      <div>
        <em>Note app, Department of Computer Science 2020</em>
      </div>
    </div>
  )
}    

每当渲染组件时, url 变化 都会执行如下命令:
const match = useRouteMatch(’/notes/:id’)
它匹配到 url 的 id, 用于 找到显示的 便笺
const note = match
? notes.find(note => note.id === Number(match.params.id))
: null


版权声明:本文为JIANG_RZJ原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。