笔记:React-router、react-router-dom、connected-react-router 学习

2020-04-15:

笔记:React-router、react-router-dom、connected-react-router 学习

https://react-guide.github.io/react-router-cn/docs/guides/basics/RouteMatching.html

https://reacttraining.com/react-router/web/api/Switch

本篇是基于一个疑问开始的:

a标签和connected-react-router中push方法都分别通过什么方式改变路由?

从结果直接说明:

1、如果使用了connected-react-router把react-router绑定到redux上,a标签才会跟redux出现关系,同时也才能使用上push;

2、a标签通过主动的方式进行跳转,react-router监听到这个行为后一方面进行路由跳转一方面通过connected-react-router发起一个action更新redux state

3、push是从redux出发,抛出一个action,再进行跳转。


一、路由配置:

  更应该使用绝对路径的理由

    1、在多层嵌套路由中使用绝对路径的能力让我们对 URL 拥有绝对的掌控。我们无需在 URL 中添加更多的层级,从而可以使用更简洁的 URL。

    2、如果一个路由使用了相对路径,那么完整的路径将由它的所有祖先节点的路径和自身指定的相对路径拼接而成。使用绝对路径可以使路由匹配行为忽略嵌套关系。

  渲染四个URL:

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

const App = React.createClass({
  render() {
    return (
      <div>
        <h1>App</h1>
        <ul>
          <li><Link to="/about">About</Link></li>    // 用Link组件替代a标签
          <li><Link to="/inbox">Inbox</Link></li>
        </ul>
        {this.props.children}
      </div>
    )
  }
})

const About = React.createClass({
  render() {
    return <h3>About</h3>
  }
})

const Inbox = React.createClass({
  render() {
    return (
      <div>
        <h2>Inbox</h2>
        {this.props.children || "Welcome to your Inbox"}
      </div>
    )
  }
})

const Message = React.createClass({
  render() {
    return <h3>Message {this.props.params.id}</h3>
  }
})

React.render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox}>
        <Route path="/messages/:id" component={Message} />

        {/* 跳转 /inbox/messages/:id 到 /messages/:id */}
        <Redirect from="messages/:id" to="/messages/:id" />     // 利用重定向兼容新旧url
      </Route>
    </Route>
  </Router>
), document.body)

二、进入和离开的Hook:

  Route 可以定义 onEnter 和 onLeave 两个 hook ,这些hook会在页面跳转确认时触发一次。这些 hook 对于一些情况非常的有用,例如权限验证或者在路由跳转前将一些数据持久化保存起来

三、路由匹配原理:

  路由拥有三个属性来决定是否“匹配“一个 URL:

  1. 嵌套关系:当一个给定的 URL 被调用时,整个集合中(命中的部分)都会被渲染。嵌套路由被描述成一种树形结构。React Router 会深度优先遍历整个路由配置来寻找一个与给定的 URL 相匹配的路由。
  2. 路径语法:路由路径是匹配一个(或一部分)URL 的 一个字符串模式
    1. 几个特殊的符号:

      • :paramName – 匹配一段位于 /? 或 # 之后的 URL。 命中的部分将被作为一个参数
      • () – 在它内部的内容被认为是可选的
      • * – 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数
        <Route path="/hello/:name">         // 匹配 /hello/michael 和 /hello/ryan
        <Route path="/hello(/:name)">       // 匹配 /hello, /hello/michael 和 /hello/ryan
        <Route path="/files/*.*">           // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg
  3. 优先级:路由算法会根据定义的顺序自顶向下匹配路由。因此,当你拥有两个兄弟路由节点配置时,你必须确认前一个路由不会匹配后一个路由中的路径。例如,千万不要这么做:
// not do this

<Route path="/comments" ... />
<Redirect from="/comments" ... />

四、History:

  React Router 是建立在 history 之上的。 简而言之,一个 history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为 location 对象, 然后 router 使用它匹配到路由,最后正确地渲染对应的组件。

history.js: 一个无刷新就可改变浏览器栏地址的插件:

  提供了window.history一系列api,目的是帮助构建单页面无刷新网站。地址修改了,而页面只有局部dom被修改,这样能省去每次都重新渲染降低性能损耗,而且能看到动态效果。

  

react-router中history的常见形式:

  1、browserHistory(更好兼容浏览器): React Router 的应用推荐的 history。它使用浏览器中的 History API 用于处理 URL,创建一个像example.com/some/path这样真实的 URL 。

    对旧版浏览器的兼容 :如果我们能使用浏览器自带的 window.history API,那么我们的特性就可以被浏览器所检测到。如果不能,那么任何调用跳转的应用就会导致 全页面刷新。

    它不需要被实例化,直接 import { browserHistory } from 'react-router',< Router history={browserHistory}>

  2、createHashHistory(方便调试) :  使用 URL 中的 hash(#)部分去创建形如 example.com/#/some/path 的路由。

五、默认路由与IndexLink:

  这是关于默认路由(首页)的配置:

  1、假如这个路由Home想使用如 onEnter hook这些路由机制时,由于其没有渲染的位置,而无法使用,此时,需要用到IndexRoute渲染Home:

<Router>
  <Route path="/" component={App}>
    <IndexRoute component={Home}/>
    <Route path="accounts" component={Accounts}/>
    <Route path="statements" component={Statements}/>
  </Route>
</Router>

  2、如果你在这个 app 中使用 <Link to="/">Home</Link> , 它会一直处于激活状态,因为所有的 URL 的开头都是 / 。 这确实是个问题,因为我们仅仅希望在 Home 被渲染后,激活并链接到它。

如果需要在 Home 路由被渲染后才激活的指向 / 的链接,请使用 <IndexLink to="/">Home</IndexLink>

(基础部分到此,高级部分可能后补)


React-router-dom:

  基于react-router(z),加入了在浏览器运行环境下的一些功能,如Switch

1、<Switch>:

  <Route> 的机制是只要匹配到的view都全部重新渲染,这样浪费性能,<Switch>做到只渲染匹配到的第一个路由的页面。


let routes = (
  <Switch>
    <Route exact path="/">
      <Home />
    </Route>
    <Route path="/about">
      <About />
    </Route>
    <Route path="/:user">
      <User />
    </Route>
    <Route>
      <NoMatch />
    </Route>
  </Switch>
);

connected-react-router:

  是一个绑定react-router到redux的组件,来实现双向绑定router的数据到redux store中,这么做的好处就是让应用更Redux化,可以在action中实现对路由的操作

// app.ts


import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {Store} from 'redux';
import {Provider} from 'react-redux';
import {Persistor} from 'redux-persist';
import {PersistGate} from 'redux-persist/integration/react';
import {ConnectedRouter} from 'connected-react-router';
import {History} from 'history';


export const render = (
    store : Store, history : History, persistor : Persistor,
) => ReactDOM.render((
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <PersistGate loading={null} persistor={persistor}>
                <App />
            </PersistGate>
        </ConnectedRouter>
    </Provider>
), document.getElementById('root'));


=====================================

// index.ts



import {createHashHistory} from 'history';
import * as moment from 'moment';
import 'moment/locale/zh-cn';

import createStore from '@main/model';
import {render} from './app';
import './index.module.less';


moment.locale('zh_cn');

export const history = createHashHistory();
const {store, persistor} = createStore(history);
store.dispatch({type : 'INITIALIZE'});

render(store, history, persistor);
原文地址:https://www.cnblogs.com/marvintang1001/p/12704761.html