React Router文件閱讀筆記(上)

周志壽發表於2019-03-14

React Router官方文件:https://reacttraining.com/react-router/web/guides/quick-start。
或許你不堪忍受閱讀英文文件的痛苦可轉至印記中文:https://react-router.docschina.org/web/guides/quick-start。
閱讀之前您最好對React的基本語法有一定的瞭解。


準備工作

安裝nod環境:

1.安裝nvm

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
複製程式碼

2.將下列程式碼新增到~/.bashrc, ~/.profile, or ~/.zshrc

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
複製程式碼

3.驗證是否安裝成功

## 如果安裝成功,應輸出“nvm”, nvm 安裝完成後,可能要重啟一下終端才有 nvm 這個命令。
command -v nvm
複製程式碼

4.安裝Node(瞭解更多請參考nvm官網

#安裝node10.15.1版本
nvm install 10.15.1
複製程式碼

官方推薦使用create-react-app建立專案

yarn create react-app my-app 或者 npx create-react-app my-app
複製程式碼

好的,一切都是那麼的順利!

BrowserRouter 和 HashRouter

  • react-router-dom將在瀏覽器中使用
  • react-router-native用於react-native app

這實際上是非常好的,因為如果我想將程式碼移植到react-native,我只需更新import語句就好了

  • 在React Router 4.0中Router已經被移除了,取而代之的是BrowserRouter和HashRouter。他們通常出現在路由的最外層。
#src/app.js部分程式碼
import { BrowserRouter as Router, Route } from "react-router-dom";

 <Router basename="/calendar">
    <div>
    <Header />
        <Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
            <Route path="/topics" component={Topics} />
    </div>
</Router>
複製程式碼
#src/components/Header.js部分程式碼
import { Link } from "react-router-dom";

const Header = () => (
    <ul>
        <li>
            <Link to="/">Home</Link> #renders <a href="/calendar">
        </li>
        <li>
            <Link to="/about">About</Link>> #renders <a href="/calendar/about">
        </li>
        <li>
            <Link to="/topics">Topics</Link>> #renders <a href="/calendar/topics">
        </li>
    </ul>
);
複製程式碼

關於他們的更多用法和區別可以參考部落格傳送門

Route

  1. path:string | string[]

可通過路由傳遞引數給元件

接受一個字串或者一個字串陣列

# 第一種用法
<Route path="/users/:id" component={User} /> # id = props.match.params.id
or
# 第二種用法
const userRoutes = [
  {
    path: '/users/create',
    component: UsersCreate
  },
  {
    path: '/users/:id',
    component: UsersShow
  },
  {
    path: '/users/:id/edit',
    component: UsersEdit
  }
]

const UserRoutes = () => (
  <Route
    exact
    path={['/users', ...userRoutes.map(route => route.path)]}
    render={() => (
      <section>
        <UsersIndex />
        <Switch>
          {userRoutes.map(route => (
            <Route key={route.path} exact path={route.path} component={route.component} />
          ))}
        </Switch>
      </section>
    )}
  />
)
複製程式碼
  1. exact: bool ( 精確匹配 )

當exact=false時,如果訪問地址包含路由路徑,則匹配成功跳轉到當前路由,反之匹配不成功。

path location.pathname exact matches
/one /one true yes
/one /one/ true yes
/one /one/two true no
/one /one false yes
/one /one/ false yes
/one /one/two false yes
  1. strict:bool ( 嚴格匹配 )

當exact=true且strict=true,真實路徑===(完全匹配)路由路徑,則匹配成功跳轉到當前路由,反之匹配不成功。可以強制路徑結尾沒有反斜槓。

path location.pathname exact matches
/one/ /one true no
/one/ /one/ true yes
/one/ /one/two true yes
  1. render:fun
#  需要注意的是:<Route component> 優先於 <Route render> 因此不要在同一個 <Route> 使用兩者。

import FadeIn from "react-fade-in";

const FadingRoute = ({ component: Component, ...rest }) => {
    return (
        <Route {...rest} render={props => (
            <FadeIn>
                <Component {...props} />
            </FadeIn>
        )} />
    )
};
const Animation = () => {
    return (
        <div>
            Animation
        </div>
    );
};

class App extends Component {
    render() {
        return (
            <div className="App">
                <Router>
                    <div>
                        <Header />
                        <Switch>
                            <FadingRoute path="/animate" component={Animation} />
                            <Route exact path="/" component={Home} />
                            <Route path="/about" component={About} />
                            <Route path="/topics" component={Topics} />
                            <Route component={NotMatch} />
                        </Switch>
                    </div>
                </Router>
            </div>
        )
    }
}

const FadingRoute = ({ component: Component, ...rest }) => {
    return (
        <Route {...rest} render={props => (
            <FadeIn>
                <Component {...props} />
            </FadeIn>
        )} />
    )
};
const Animation = () => {
    return (
        <div>
            Animation
        </div>
    );
};

class App extends Component {
    render() {
        return (
            <div className="App">
                <Router>
                    <div>
                        <Header />
                        <Switch>
                            <FadingRoute path="/animate" component={Animation} />
                            <Route exact path="/" component={Home} />
                            <Route path="/about" component={About} />
                            <Route path="/topics" component={Topics} />
                            {/*<Route component={NotMatch} />*/}
                        </Switch>
                    </div>
                </Router>
            </div>
        )
    }
}
複製程式碼
  1. children: func
# 下面程式碼類似於官方文件 Custom Link例子
const MenuLink = ({ children, to, exact }) => {
    return (
        <Route path={to} exact={exact} children={({ match }) => {
            return (
                <NavLink activeStyle={match ? { color: "#ff00ff" } : {}} to={to}>
                    {match ? ">" : ""}{children}
                </NavLink>
            );
        }} />
    );
};

class App extends Component {
    handleClick = () => {
        console.log(this.props);
    };
    
    render() {
        return (
            <Router>
                <div className="App">
                    <header className="App-header">
                        <img src={logo} className="App-logo" alt="logo" />
                        <h1 className="App-title">Welcome to React</h1>
                    </header>
                    <div className="App-intro">
                        <ul>
                            <li>
                                <MenuLink exact={true} to="/">
                                    Home
                                </MenuLink>
                            </li>
                            <li>
                                <MenuLink exact={true} to="/about">
                                    About
                                </MenuLink>
                            </li>
                        </ul>
                        <Switch>
                            <Route exact path="/" component={Home} />
                            <Route strict exact path="/about" component={About} />
                            <Route component={NoMatch} />
                        </Switch>
                    </div>
                </div>
            </Router>
        );
    }
}
複製程式碼

Link

Link的表現形式類似於a標籤,但是功能更強大。

import { Link } from 'react-router-dom'
## 宣告式
<Link to="/about" className='active'>About</Link>
## 程式設計式
props.history.push("/about");

<Link to='/courses?sort=name'/>

<Link to={{
  pathname: '/courses',
  search: '?sort=name',
  hash: '#the-hash',
  state: { fromDashboard: true }
}}/>
#掛載好的Link可以對其進行DOM操作
const refCallback = node => {
  node.getAttribute("href"); # /
}
<Link to="/" innerRef={refCallback} />
複製程式碼

NavLink

給匹配到的路由新增樣式,是一種特殊的Link,在用法上大致相同

import { NavLink } from 'react-router-dom

<NavLink to="/faq"activeClassName="selected"> NavLink </NavLink> 

<NavLink to="/faq"
activeStyle={{ fontWeight: 'bold',color: 'red' }}>
  NavLink
</NavLink>

複製程式碼

有時為了確定連結是否處於活動狀態而新增額外邏輯

import queryString from "query-string";

const getQuery = (match, location) => {
if (!match) {
    return false
  }
  const query = queryString.parse(location.search).job;
  return query;
};
<NavLink to="/faq?job=FE"
activeClassName="selected"
isActive={ getQuery }> NavLink </NavLink> 
複製程式碼

Switch

Switch用來包裹Route,它裡面不能放其他元素。結合以下程式碼舉個栗子:使用者輸入一個URL是'/about',假設沒有Switch存在,那麼根據前面所提到的路由匹配規則About、Users、NotMatch都將被渲染。由於Switch從上至下匹配Route,查詢到<Route path="/about" component={About}>時停止搜尋並只會渲染About元件。

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

<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/about" component={About} />
    <Route path="/:id" component={Users} />
    <Route component={NotMatch} />
</Switch>
複製程式碼

WithRouter

Wrapper元件一開始並沒有註冊路由,不會有路由屬性的傳遞(match、location和history)。但是可以通過WithRouter高階元件訪問 history物件的屬性和最近的 的 match,當路由渲染時,withRouter會將已經更新的 match、location和history 屬性傳遞給被包裹的元件。

# src/components/Home.js部分程式碼

import React from "react";
import { withRouter } from "react-router";

const Wrapper = ({ history }) => {
    return (
        <div>
            <button onClick={() => history.push("/about")}>Hello</button>
        </div>
    );
};
const WithRouterWrapper = withRouter(Wrapper);
const Home = (props) => {
    return (
        <div>
            <h1>Home</h1>
            <button onClick={() => {
                props.history.push("/about");
            }}>前往about頁面
            </button>
            <WithRouterWrapper />
        </div>
    );
};
export default Home;

複製程式碼

相關文章