Maison  >  Article  >  interface Web  >  Analyse complète des connaissances de React Router (exemples de code)

Analyse complète des connaissances de React Router (exemples de code)

不言
不言original
2018-09-17 14:06:441251parcourir

Ce que cet article vous apporte est une analyse complète des connaissances de React Router (exemples de code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

1. Routage front-end et routage back-end

1) Routage back-end

Dans une application multipage, une URL correspond à une page HTML, et une application Web contient de nombreuses pages HTML. Dans les applications multipages, le contrôle du routage des pages est géré par le serveur. Cette méthode de routage est appelée routage back-end.

Dans les applications multipages, chaque changement de page doit envoyer une requête au serveur, et les ressources statiques utilisées par la page doivent également être rechargées, ce qui implique une certaine quantité de gaspillage. De plus, le rafraîchissement global de la page a également un impact sur l'expérience utilisateur, car il existe souvent des parties communes entre les différentes pages, comme les barres de navigation, les barres latérales, etc., et le rafraîchissement global de la page entraînera également le rafraîchissement de parties communes.

2) Routage front-end

Dans une application monoface, l'URL n'envoie pas de nouvelle requête au serveur, le routage de la "page logique" ne peut donc être géré que par le front-end. Ce type de routage Cette méthode est appelée routage front-end.

À l'heure actuelle, la plupart des moteurs de recherche nationaux ne prennent pas bien en charge le référencement des applications d'une seule page. Par conséquent, pour les applications Web
(par exemple, les sites Web officiels d'entreprise, les sites Web de commerce électronique, etc.). sont très importants pour le référencement, en général. Ou choisirez-vous d'utiliser une application multipage. React ne sert pas uniquement à développer des applications d'une seule page.

2. Installation de React Router

Le numéro de version majeur de React Router utilisé ici est la v4, qui est également la dernière version.

React Router comprend 3 bibliothèques, React-Router, React-Router-Dom et React-Router-Native. React-Router fournit la fonction de routage la plus basique. En utilisation réelle, nous n'installerons pas React-Router directement, mais choisirons d'installer React-Router-dom (utilisé dans le navigateur) ou React-Router-native (basé sur). l'environnement dans lequel l'application est exécutée). React-router-dom et React-Router-native dépendent de React-Router, donc lors de l'installation, React-Router sera également installé automatiquement.
Pour créer une application Web, utilisez

npm install react-router-dom

pour créer une application navtive, utilisez

 npm install react-router-native

3. Le routeur

Le routeur React est complété via le deux composants : routeur et fonction de routage d'itinéraire. Le routeur peut être compris comme un routeur. Une application nécessite une instance de routeur. Tous les composants de configuration du routeur sont définis comme des sous-composants du routeur. Dans les applications Web, nous utilisons généralement deux composants, BrowserRouter ou HashRouter, qui encapsulent RouterRouter qui utilise l'API d'historique HTML5 (pushState, replaceState, etc.) pour synchroniser l'interface utilisateur et l'URL de l'application. HashRouter utilise le hachage de l'URL pour synchroniser l'interface utilisateur de l'application et l'URL.

L'URL créée par BrowserRouter est sous la forme suivante :

http://example.com/some/path

L'URL créée par HashRouter est sous la forme suivante :

 http://example.com/#/some/path

Lors de l'utilisation de BrowserRouter, vous devez généralement configurer le serveur. Autoriser le serveur à gérer correctement toutes les URL possibles. Par exemple, lorsque le navigateur effectue deux requêtes http://example.com/some/path et http://example.com/some/path2, le serveur doit pouvoir renvoyer la bonne page HTML (c'est-à-dire la uniquement une page HTML dans une application monopage) Page HTML)

HashRouter n'a pas ce problème, car le contenu de la partie de hachage sera automatiquement ignoré par le serveur. L'information vraiment efficace est le front de hachage. partie finale, et pour les applications d'une seule page, cette partie est fixe.

Le routeur créera un objet d'historique et l'historique est utilisé pour suivre l'URL. Lorsque l'URL change, les composants descendants du routeur seront restitués. D'autres composants fournis dans React Router peuvent obtenir l'objet historique via le contexte, ce qui indique également implicitement que d'autres composants de React Router doivent être utilisés en tant que descendants du composant Router. Mais il ne peut y avoir qu'un seul élément enfant dans Router, par exemple :

// 正确
ReactDOM.render(
  (
  <BrowserRouter>
    <App />
  </BrowserRouter>),
  document.getElementById('root')
)
//错误,Router 中包含两个子元素
ReactDOM.render(
  (
    <BrowserRouter>
      <App1 />
      <App2 />
    </BrowserRouter>),
  document.getElementById('root')
)

4. Router

Route est le composant utilisé pour configurer les informations de routage dans React Router, et est également la fréquence d'utilisation dans React Router Le composant le plus élevé. Chaque fois qu'un composant doit décider s'il doit être rendu en fonction de l'URL, vous devez créer une route.

1) chemin

Chaque route doit définir un attribut de chemin. Lors de l'utilisation de BrowserRouter, le chemin est utilisé pour décrire le nom de chemin de l'URL correspondant à ce routeur. Lors de l'utilisation de HashRouter, le chemin est utilisé. to Décrit le hachage de l'URL correspondant à cette route. Par exemple, lorsque vous utilisez BrowserRouter, correspondra à une URL dont le chemin commence par foo (par exemple : http://example.com/foo). Lorsque l'URL correspond à une route, les composants définis dans la route seront rendus.

2)match

Lorsque l'URL et la Route correspondent, Route créera un objet de correspondance et le transmettra au composant rendu en tant qu'attribut dans les accessoires. Cet objet contient les 4 propriétés suivantes.

(1) params : le chemin de la route peut contenir des paramètres, par exemple

(2) isExact : est une valeur booléenne lorsque l'URL correspond complètement, la valeur est vraie ; lorsque l'URL correspond partiellement, la valeur est fausse. Par exemple, lorsque path='/foo', URL. ="http ://example.com/foo", il s'agit d'une correspondance exacte ; lorsque URL="http://example.com/foo/1", il s'agit d'une correspondance partielle.

(3)path: Route 的 path 属性,构建嵌套路由时会使用到。

(4)url: URL 的匹配的方式

3)Route 渲染组件的方式

(1)component

component 的值是一个组件,当 URL 和 Route 匹配时,Component属性定义的组件就会被渲染。例如:

<Route path=&#39;/foo&#39; component={Foo} ></p>
<p>当 URL = "http://example.com/foo" 时,Foo组件会被渲染。</p>
<p>(2) render<br>render 的值是一个函数,这个函数返回一个 React 元素。这种方式方便地为待渲染的组件传递额外的属性。例如:</p>
<pre class="brush:php;toolbar:false"><Route path=&#39;/foo&#39; render={(props) => {
  <Foo {...props} data={extraProps} />
}}>
</Route>

Foo 组件接收了一个额外的 data 属性。

(3)children
children 的值也是一个函数,函数返回要渲染的 React 元素。 与前两种方式不同之处是,无论是否匹配成功, children 返回的组件都会被渲染。但是,当匹配不成功时,match 属性为 null。例如:

<Route path=&#39;/foo&#39; render={(props) => {
  <p className={props.match ? &#39;active&#39;: &#39;&#39;}>
    <Foo {...props} data={extraProps} />
  </p>
}}>
</Route>

如果 Route 匹配当前 URL,待渲染元素的根节点 p 的 class 将设置成 active.

4)Switch 和 exact

当URL 和多个 Route 匹配时,这些 Route 都会执行渲染操作。如果只想让第一个匹配的 Route 沉浸,那么可以把这些 Route 包到一个 Switch 组件中。如果想让 URL 和 Route 完全匹配时,Route才渲染,那么可以使用 Route 的 exact 属性。Switch 和 exact 常常联合使用,用于应用首页的导航。例如:

<Router>
 <Switch>
    <Route exact path=&#39;/&#39; component={Home}/>
    <Route exact path=&#39;/posts&#39; component={Posts} />
    <Route exact path=&#39;/:user&#39; component={User} />
  </Switch>
</Router>

如果不使用 Switch,当 URL 的 pathname 为 "/posts" 时, 都会被匹配,但显然我们并不希望 被匹配,实际上也没有用户名为 posts 的用户。如果不使用 exact, "/" "/posts" "/user1"等几乎所有 URL 都会匹配第一个 Route,又因为Switch 的存在,后面的两个 Route永远不会被匹配。使用 exact,保证 只有当 URL 的 pathname 为 '/'时,第一个Route才会匹配。

5)嵌套路由

嵌套路由是指在Route 渲染的组件内部定义新的 Route。例如,在上一个例子中,在 Posts 组件内再定义两个 Route:

const Posts = ({match}) => {
  return (
    <p>
      {/* 这里 match.url 等于 /posts */}
      <Route path={`${match.url}/:id`} component={PostDetail} />
      <Route exact path={match.url} component={PostList} />
    </p>
  )
}

五、链接

Link 是 React Router提供的链接组件,一个 Link 组件定义了当点击该 Link 时,页面应该如何路由。例如:

const Navigation = () => {
  <header>
    <nav>
      <ul>
        <li><Link to=&#39;/&#39;>Home</Link></li>
        <li><Link to=&#39;/posts&#39;>Posts</Link></li>
      </ul>
    </nav>
  </header>
}

Link 使用 to 属性声明要导航到的URL地址。to 可以是 string 或 object 类型,当 to 为 object 类型时,可以包含 pathname、search、hash、state 四个属性,例如:

<Link to={{
  pathname: &#39;/posts&#39;,
  search: &#39;?sort=name&#39;,
  hash:&#39;#the-hash&#39;,
  state: { fromHome: true}
}}>
</Link>

除了使用Link外,我们还可以使用 history 对象手动实现导航。history 中最常用的两个方法是 push(path,[state]) 和 replace(path,[state]),push会向浏览器记录中新增一条记录,replace 会用新记录替换记录。例如:

history.push('/posts');
history.replace('/posts');

六、路由设计

路由设计的过程可以分为两步:

  1. 为每一个页面定义有语义的路由名称(path)

  2. 组织 Route 结构层次

1)定义路由名称

我们有三个页面,按照页面功能不难定义出如下的路由名称:

  • 登录页: /login

  • 帖子列表页: /posts

  • 帖子详情页: /posts/:id(id代表帖子的ID)

但是这些还不够,还需要考虑打开应用时的默认页面,也就是根路径"/"对应的页面。结合业务场景,帖子列表作为应用的默认页面为合适,因此,帖子列表对应两个路由名称: '/posts'和 '/'

2)组织 Route 结构层次

React Router 4并不需要在一个地方集中声明应用需要的所有 Route, Route实际上也是一个普通的 React 组件,可以在任意地方使用它(前提是,Route必须是 Router 的子节点)。当然,这样的灵活性也一定程度上增加了组织 Route 结构层次的难度。
我们先考虑第一层级的路由。登录页和帖子列表页(首页)应该属于第一层级:

<Router>
  <Switch>
    <Route exact path="/" component={Home}></Route>
    <Route exact path="/login" component={Login}></Route>
    <Route exact path="/posts" component={Home}></Route>
  </Switch>
</Router>

第一个Route 使用了 exact 属性,保证只有当访问根路径时,第一个 Route 才会匹配成功。Home 是首页对应组件,可以通过 "/posts" 和 “/” 两个路径访问首页。注意,这里并没有直接渲染帖子列表组件,真正渲染帖子列表组件的地方在 Home 组件内,通过第二层级的路由处理帖子列表组件和帖子详情组件渲染,components/Home.js 的主要代码如下:

class Home extends Component {
  /**省略其余代码 */
  render() {
    const {match, location } = this.props;
    const { username } = this.state;
    return(
      <p>
        <Header
          username = {username}
          onLogout={this.handleLogout}
          location = {location}
        >
        </Header>
        {/* 帖子列表路由配置 */}
        <Route
          path = {match.url}
          exact
          render={props => <PostList username={username} {...this.props}></PostList>}
        ></Route>
      </p>
    )
  }
}

Home的render内定义了两个 Route,分别用于渲染帖子列表和帖子详情。PostList 是帖子列表组件,Post是帖子详情组件,代码使用Router 的render属性渲染这两个组件,因为它们需要接收额外的 username 属性。另外,无论访问是帖子列表页面还是帖子详情页面,都会共用相同 Header 组件。

七、代码分片

默认情况下,当在项目根路径下执行 npm run build 时 ,create-react-app内部使用 webpack将 src路径下的所有代码打包成一个 JS 文件和一个 Css 文件。

当项目代码量不多时,把所有代码打包到一个文件的做法并不会有什么影响。但是,对于一个大型应用,如果还把所有的代码都打包到一个文件中,显然就不合适了。

create-react-app 支持通过动态 import() 的方式实现代码分片。import()接收一个模块的路径作为参数,然后返回一个 Promise 对象, Promise 对象的值就是待导入的模块对象。例如

// moduleA.js

const moduleA = 'Hello'
export { moduleA };

// App.js

import React, { Component } from 'react';

class App extends Component {
  handleClick = () => {
    // 使用import 动态导入 moduleA.js
    import('./moduleA')
      .then(({moduleA}) => {
        // 使用moduleA
      })
      .catch(err=> {
        //处理错误
      })
  };
  render() {
    return(
      <p>
        <button onClick={this.handleClick}>加载 moduleA</button>
      </p>
    )
  }
}

export default App;

上面代码会将 moduleA.js 和它所有依赖的其他模块单独打包到一个chunk文件中,只有当用户点击加载按钮,才开始加载这个 chunk 文件。
当项目中使用 React Router 是,一般会根据路由信息将项目代码分片,每个路由依赖的代码单独打包成一个chunk文件。我们创建一个函数统一处理这个逻辑:

import React, { Component } from 'react';
// importComponent 是使用 import()的函数
export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    constructor(props) {
      super(props);
      this.state = {
        component:  null //动态加载的组件
      }
    }
    componentDidMount() {
      importComponent().then((mod) => {
        this.setState({
          // 同时兼容 ES6 和 CommonJS 的模块
          component: mod.default ? mod.default : mod;
        });
      })
    }
    render() {
      // 渲染动态加载组件
      const C = this.state.component;
      return C ? <C {...this.props}></C> : null
    }
  }

  return AsyncComponent;
}

asyncComponent接收一个函数参数 importComponent,  importComponent 内通过import()语法动态导入模块。在AsyncComponent被挂载后,importComponent就会阴调用,进而触发动态导入模块的动作。
下面利用 asyncComponent 对上面的例子进行改造,代码如下:

import React, { Component } from 'react';
import { ReactDOM, BrowserRouter as Router, Switch, Route } from 'react-dom';
import asyncComponent from './asyncComponent'
//通过asyncComponent 导入组件,创建代码分片点
const AsyncHome = asyncComponent(() => import("./components/Home"))
const AsyncLogin = asyncComponent(() => import("./components/Login"))

class App extends component {
  render() {
    return(
      <Router>
        <Switch>
          <Route exact path="/" component={AsyncHome}></Route>
          <Route exact path="/login" component={AsyncLogin}></Route>
          <Route exact path="/posts" component={AsyncHome}></Route>
        </Switch>
      </Router>
    )
  }
}

export default App;

这样,只有当路由匹配时,对应的组件才会被导入,实现按需加载的效果。

这里还有一个需要注意的地方,打包后没有单独的CSS文件了。这是因为 CSS样子被打包到各个 chunk 文件中,当 chunk文件被加载执行时,会有动态把 CSS 样式插入页面中。如果希望把 chunk 中的 css打包到一个单独的文件中,就需要修改 webpack 使用的 ExtractTextPlugin 插件的配置,但 create-react-app 并没有直接把 webpack 的配置文件暴露给用户,为了修改相应配置
,需要将 create-react-app 管理的配置文件“弹射”出来,在项目根路径下执行:

npm run eject

项目中会多出两个文件夹:config和 scripts,scrips中包含项目启动、编译和测试的脚本,config 中包含项目使用的配置文件,
webpack配置文件 就在这个路径下,打包 webpack.config.prod.js 找到配置 ExtractTextPlugin 的地方,添加 allChunks:true 这项配置:

new ExtractTextPlugin({
  filename: cssFilename,
  allChunks: true
})

然后重新编译项目,各个chunk 文件 使用的 CSS 样式 又会统一打包到 main.css 中。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn