react 创建新的项目以及react-router4.xx 配

2018-08-17  本文已影响0人  Lyan_2ab3

背景日常絮叨

看到这个文章 大部分也是react 有基础或者刚入门的小伙伴,react 目前比较流行 欢欣的一个库,下面让我们一步一步run 起来

路由跳转是指在同步保持浏览器URL的过程中渲染页面中的视图。React Router 让你声明式的操作路由跳转。声明式路由方法允许你控制应用中的数据流.

创建新的react 项目

但是打开项目会发现,一些与webpack相关的东西被隐藏掉了,只需要做单独的配置键入下面的命令

在运行之前 可以安装一个react-router

为了方便管理复用,我一般都会拆分组件,src 里面 创建 文件page route component ,如下图:

1.jpeg

react-router

路由组件:BrowserRouter 和HashRouter
路径匹配的组件: Route 和 Switch
导航组件: Link

export default (
  <Router history={historyConfig}>
   <div>
      <ul className="nav">
      <li><Link to="/">App</Link></li>
      <li><Link to="/About">About</Link></li>
      <li><Link to="/User">User</Link></li>
          <li><Link to="/Detail">Detail</Link></li>
     </ul>
    <hr />
    <Route exact path="/" component={Home} />
    <Route path="/About" component={About} />
    <Route path="/User" component={User} />
    <Route path="/Detail" component={DeatilComponent} />
</div>
  </Router>
);

Router组件决定了我们使用html5 history api,
Route组件定义了路由的匹配规则和渲染内容,
使用 Link 组件进行路由之间的导航。
使用 exact 属性来定义路径是不是精确匹配。

Router

我们都知道 React Router API 中有两种类型的路由

<BrowserRouter> http://localhost:300/home 比较常用
<HashRouter> 哈希路由 http://localhost:300/#/home

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

将 BrowserRouter 修改为 HashRouter 就可以了,基本不需要修改其他东西。

Route常用属性

主要职责是当Route的位置和路径匹配的时候渲染对应的ui

exact、path以及component属性
Route会向component组件传一个参数,包含属性match,location,history。match属性对象又包含url,path,params等属性。比较常用的就是match的url属性,可以继续基于url指定组件里面的Link标签要链接到的url,从而显示对应的组件。

Route写在哪里,当Route匹配到URL的时候,相应的组件就会在那里进行渲染。component,render,children,Route的这三个属性写一个就行,不能同时都写。precendence order: component > render > children.

注意:children中的元素不管是否匹配到URL都会渲染,不过没有匹配到的Route向children的函数中传的值是null,只有匹配到的时候才会有值。

<Route>是如何渲染的?

当路由 match 成功之后,route 根据


$ npm install --save history
createBrowserHistory

import createBrowserHistory from 'history/createBrowserHistory';
const historyConfig = createBrowserHistory({
basename: '/' + AREA_ENV

});

history有三种使用方式:

createBrowserHistory({
basename: '', // 基链接
forceRefresh: false, // 是否强制刷新整个页面
keyLength: 6, // location.key的长度
getUserConfirmation: (message,callback) => callback(window.confirm(message)) // 跳转拦截函数 })

createMemoryHistory({
initialEntries: ['/'], // 初始载入路径,和MemoryRouter中的initialEntries是一样的 initialIndex: 0, // initialEntries初始载入索引
keyLength: 6, // location.key的长度
getUserConfirmation: null // 路由跳转拦截函数 })

Switch :

渲染与该地址匹配的第一个子节点 <Route> 或者 <Redirect>。外面包一层Switch 和不用Switch 有什么不同呢?

下面的代码 所有的路由 都会渲染出来,那么如果有些需求比如 侧栏,面包屑那么我们只能选择一个 路由渲染出来

    <Route exact path="/" component={Home} />
    <Route path="/Detail" component={PrivateRoute}  />
    <Route path="/About" component={About} />
    <Route path="/User" component={User} />

所以使用 Switch 实现

<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/Detail" component={PrivateRoute}  />
    <Route path="/About" component={About} />
    <Route path="/User" component={User} />
</Switch>

Link:

导航到指定的路由


react-router 的基本原理:

实现URl 和UI界面的同步,其中在react-router中,URL对应location 对象,而UI对应的是react components 来决定,这样就是 location 和 components 的同步的问题。

// 内部的抽象实现
function createHistory(options={}) {
  ...
  return {
    listenBefore, // 内部的hook机制,可以在location发生变化前执行某些行为,AOP的实现
    listen, // location发生改变时触发回调
    transitionTo, // 执行location的改变
    push, // 改变location
    replace,
    go,
    goBack,
    goForward,
    createKey, // 创建location的key,用于唯一标示该location,是随机生成的
    createPath,
    createHref,
    createLocation, // 创建location
  }
}
location = {
  pathname, // 当前路径,即 Link 中的 to 属性
  search, // search
  hash, // hash
  state, // state 对象
  action, // location 类型,在点击 Link 时为 PUSH,浏览器前进后退时为 POP,调用 replaceState 方法时为 REPLACE
  key, // 用于操作 sessionStorage 存取 state 对象
};
检测url 前进:

hashChange 监听window.location.hash 的变化,hash 发生变化,浏览器更新url,同时history 栈中会产生一条新的记录。
在 react-router 内部注册了 window.addEventListener('hashchange', listener, false) 事件监听器, listener 内部可以通过 hash fragment 获取到当前 URL 对应的 location 对象

pushState: window.history.pushState(state, title, path)方法 ,改变浏览器的url,通过location.state 来获取到 state,在 react-router内部将该对象存储到了 sessionStorage 中

检测url 回退:

路由匹配原理:

路由有三个属性决定是否匹配一个URL;

1、嵌套关系

当一个给定的 URL 被调用时,整个集合中(命中的部分)都会被渲染。嵌套路由被描述成一种树形结构。React Router 会深度优先遍历整个路由配置来寻找一个与给定的 URL 相匹配的路由。

2、路径语法

<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、优先级

路由是自顶向下匹配路由,确保前一个路由不会匹配后一个路由的路径


BrowserRouter 和HashRouter 区别

BrowserRouter:

vue:mode:history
react: <BrowserRouter>

pushState, replaceState会改变当前路径,但是他不会导致单页面的重新渲染,我们所使用时,页面的渲染是由react或vue中的Router中监听了路由的变化

// 监听路由变化
this.unlisten = props.history.listen(location => {
  if (this._isMounted) {
      this.setState({ location });
  } else {
      this._pendingLocation = location;
  }
});
// 以下就是Route在当路由发生变化时做的渲染
{props.match
  ? children
    ? typeof children === "function"
      ? __DEV__
        ? evalChildrenDev(children, props, this.props.path)
        : children(props)
      : children
    : component
    ? React.createElement(component, props)
    : render
    ? render(props)
    : null
  : typeof children === "function"
  ? __DEV__
    ? evalChildrenDev(children, props, this.props.path)
    : children(props)
  : null}

当刷新页面时,浏览器会向服务器请求example.com/list,服务器实际会去找根目录下list.html这个文件,发现找不到,因为实际上我们的服务器并没有这样的 物理路径/文件 或没有配置处理这个路由,所有内容都是通过React-Router去渲染React组件,自然会报404错误。这种情况我们可以通过配置Nginx或通过自建Node服务器来解决。

hashHistory:

vue:mode:hash
react: <HashRouter>

从BrowserRouter.js和HashRouter.js文件中可以看到,history对象是由history插件生成的

// BrowserRouter.js
import { createBrowserHistory as createHistory } from "history";
history = createHistory(this.props);
 
// 用于createHistory传入的配置对象参数,也说明了这个配置是有父级传递的,而不是BrowserRouter自身的
BrowserRouter.propTypes = {
   basename: PropTypes.string,
   children: PropTypes.node,
   forceRefresh: PropTypes.bool,
   getUserConfirmation: PropTypes.func,
   keyLength: PropTypes.number
};
 
// HashRouter.js
import { createHashHistory as createHistory } from "history";
history = createHistory(this.props);
 
// 用于createHistory传入的配置对象参数
HashRouter.propTypes = {
   basename: PropTypes.string,
   children: PropTypes.node,
   getUserConfirmation: PropTypes.func,
   hashType: PropTypes.oneOf(["hashbang", "noslash", "slash"])
};

createMemoryHistory:

React-router 按需加载方式:

一: create-react-app

import React from 'react';

export default function (getComponent) {
  return class AsyncComponent extends React.Component {
    static Component = null;
    state = { Component: AsyncComponent.Component };

    componentWillMount() {
      if (!this.state.Component) {
        getComponent().then(({default: Component}) => {
          AsyncComponent.Component = Component
          this.setState({ Component })
        })
      }
    }
    render() {
      const { Component } = this.state
      if (Component) {
        return <Component {...this.props} />
      }
      return null
    }
  }
}

import asyncComponent from './asyncComponent'
const Login = asyncComponent(() => load('login/login'))
const LayoutPage = asyncComponent(() => load('layout/layout'))
const NoticeDeatil = asyncComponent(() => load('noticeDetail/noticeDetail'))
export const appRouterMap = [
    {path:"/login",name:"Login",component:Login,auth:false},
    {path:"/web",name:"LayoutPage",component:LayoutPage,auth:false},
    {path:"/notice/:id",name:"NoticeDeatil",component:NoticeDeatil,auth:false},
]

二、借助react-loadable来实现按需加载

1、利用react-loadable这个高级组件,要做到实现按需加载这一点

第三种 bundle-loader 按需加载方式


不管vue 还是react 都可以使用

hash路由:

hash原理是触发了onhashchange 事件,

hash —— 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello。
它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。

window.onhashchange = function(event){
    console.log(event.oldURL, event.newURL);
    let hash = location.hash.slice(1);
    document.body.style.color = hash; 
}

前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求。

history路由:

history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。

history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,http://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。
Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”

Vue-Router HTML5 History 模式

上一篇下一篇

猜你喜欢

热点阅读