Tìm hiểu react router v4

Giới thiệu

React-router được dùng để giúp việc dẫn hướng UI đồng bộ với URL.

Ví dụ ta có 1 trang home sẽ hiển thị lời chào và các nội dung liên quan. Chi tiết trang web sẽ được tìm thấy ở trang "About", danh sách người dùng ở 1 trang khác và các trang liên quan khác ... Để có thể điều hướng qua được các component about và topic thì trong reactjs ta sử dụng thêm thư viện điều hướng react-router ví dụ implement screen trên như sau:

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

const BasicExample = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

export default BasicExample

Cài đặt

React Router về cơ bản đều giống nhau và chúng được sử dụng chia thành 3 package: react-router, react-router-dom and react-router-native.

react-router-dom: dành cho ứng dụng web. react-router-native: dành cho ứng dụng mobile. react-router-core: sử dụng bất cứ lúc nào với các ứng dụng lõi.

Vì ta chỉ sử dụng cho web ta chỉ cần cài đặt dependency:

npm install --save react-router-dom

Ta sẽ import Component "BrowerRouter" từ thư viện "react-router-dom" cùng với "Link" và "Route" giống như đoạn code giới thiệu bên trên.


import {
BrowserRouter,
Route,
Link
} from 'react-router-dom'

Bây giờ ta sẽ đi tìm hiểu chi tiết các các component trong react-router.

BrowserRouter

A <Router> that uses the HTML5 history API (pushState, replaceState and the popstate event) to keep your UI in sync with the URL.

Trong React, Router sẽ kiểm tra History cho mỗi Component và bất cứ khi nào có thay đổi trong History, Component đó sẽ được render lại. Trước khi có React Router v4, ta phải set giá trị History thủ công. Việc này đã được tự động ở Router v4 bằng thẻ <BrowserRouter>. Nếu bạn vẫn cần truy cập vào History, HTML5 cung cấp 1 API có sẵn cho phép điều chỉnh đối tượng History thông qua các phương thức pushState và replaceState.

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

<BrowserRouter
  basename={optionalString}
  forceRefresh={optionalBool}
  getUserConfirmation={optionalFunc}
  keyLength={optionalNumber}
>
  <App/>
</BrowserRouter>

basename: string

<BrowserRouter basename="/calendar"/>
<Link to="/today"/> // renders <a href="/calendar/today">

getUserConfirmation: func // A function to use to confirm navigation. Defaults to using window.confirm.

// this is the default behavior
const getConfirmation = (message, callback) => {
  const allowTransition = window.confirm(message)
  callback(allowTransition)
}

<BrowserRouter getUserConfirmation={getConfirmation}/>

Link

Link được sử dụng để điều hướng, và truy cập xung quanh các navigation của app. Nó tương đương với thẻ <a></a>.

Tham số được truyền vào Link là "to", nhận vào đường dẫn url.

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

<Link to="/about">About</Link>

Route

Router là thành phần quan trọng nhất trong react-router. Nó sẽ chịu trách nhiệm các chắc năng như sau:

  1. Tạo Component được chỉ định trong <Route>.
  2. Sử dụng hàm render. <Route> sẽ trả về null trong trường hợp url nhập vào không trùng với path định nghĩa. <Route> về cơ bản nhận vào 2 tham số, 1 là path và còn lại là component sẽ render.

Dưới đây là ví dụ:

import { BrowserRouter as Router, Route } from 'react-router-dom'

<Router>
  <div>
    <Route exact path="/" component={Home}/>
    <Route path="/news" component={NewsFeed}/>
  </div>
</Router>

nó sẽ chịu trách nhiệm render UI dưạ vào path như sau nếu path là ''/" thì UI sẽ như:

<div>
  <Home/>
  <!-- react-empty: 2 -->
</div>

nếu path "/news" thì UI:

<div>
  <!-- react-empty: 1 -->
  <NewsFeed/>
</div>

IndexRoute được thay thế bằng từ khóa "exact".

Với v4 ta không cần IndexRoute để render trang home nữa. Thay vào đó ta sử dụng props "exact" như ví dụ phía trên.

Route trong phiên bản 4 này còn có ý nghĩa rằng có thể có nhiều hơn 1 route được render cùng lúc. Ta tận dụng props "exact" để giải quyết sự bất đồng khi có nhiều path match thay vì chỉ 1.

Trong ví dụ trên, nếu không sử dụng "exact", đường dẫn "/" sẽ match với cả "/", "/about", "/topic". Tuy nhiên ta chỉ muốn nó match với Route chứa hàm render, và sử dụng "exact" sẽ giải quyết được điều này.

Redirect

Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

Switch

Ở phần trước đã biểu diễn cách gói nhiều route vào trong 1 thẻ

, thì ở phần này khi muốn render chỉ 1 Component trong 1 thời điểm, ta dùng thẻ tag <Switch>. Nó sẽ có ý nghĩa: kiểm tra path có match hay không tuần tự từ trên xuống và ngừng lại ở path đầu tiên match với đường dẫn nhập vào.

import { Switch, Route } from 'react-router'

<Switch>
  <Route exact path="/" component={Home}/>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Switch>

location

Router sẽ cung cấp cho bạn một object location, nó được sử dụng rất nhiểu trong dự án. Object nó sẽ trông như thế này:

{
  key: 'ac3df4', // not with HashHistory!
  pathname: '/somewhere'
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}

Cuối cùng thì bạn cũng đã có những hiểu biết cơ bản về React Router v4. Dưới đây là đoạn code tổng hợp nội dung của bài viết này.

const App= () => (
  <BrowserRouter>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>
      <Route exact path="/" render={ ( ) => (<h2> HomePage </h2>) } />
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </BrowserRouter>
)