在咱们使用React来构建单页App的时候,最大的区别是,导航一个页面应用程序并不涉及到一个全新的页面。而是你的整个应用是在同一个页面进行操做的。当你加载网页内容的时候,将会变得有一点困难,困难的部分不是加载内容自己,这相对来讲比较容易,而是确保单页应用的行为与用户习惯性的操做行为保存一致,更显著的是,当用户导航使用你的App时候,有如下几点问题:html
对于多页应用,这三点是不用去考虑的,也没有额外的你不得不去为多页应用考虑的。而对于单页应用,由于你不能导航到一个完成新的页面,你不得不真正的去处理这三个你的用户指出的问题。你须要确保导航进入你的App的URL是彻底正确的。你须要确保浏览器的历史记录每一个导航都是同步的来准许用户使用后退或前进按钮。若是用户标记(收藏)了某个特殊的视图或复制粘贴了一URL以便以后能够访问,你须要确保的是你的单页应用可以将用户引导正确的位置。为了处理以上的问题,你须要有一门一般叫作路由的技术。react
create-react-app react_spa cd react_spa npm i react-router-dom --save
将原来项目中public与src文件夹下的全部文件(夹)删除,而后在public文件夹下建立一个index.html将服务于咱们App的开始入口。git
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <title>React Router Example</title> </head> <body> <div id="root"></div> </body> </html>
以后在src文件夹下建立一个index.js文件做为咱们的入口文件,并添加下面内容:github
import React from "react"; import ReactDOM from "react-dom"; import Main from "./Main"; ReactDOM.render( <Main/>, document.getElementById("root") );
接下来在src文件夹下面建立一个Main.js文件做为路由的配置文件:npm
import React, { Component } from "react"; class Main extends Component { render() { return ( <div> <h1>Simple SPA</h1> <ul className="header"> <li><a href="/">Home</a></li> <li><a href="/stuff">Stuff</a></li> <li><a href="/contact">Contact</a></li> </ul> <div className="content"> </div> </div> ); } } export default Main;
构建内容页面:api
Home.js浏览器
import React, { Component } from "react"; class Home extends React.Component { render() { return ( <div> <h2>HELLO</h2> <p>Cras facilisis urna ornare ex volutpat, et convallis erat elementum. Ut aliquam, ipsum vitae gravida suscipit, metus dui bibendum est, eget rhoncus nibh metus nec massa. Maecenas hendrerit laoreet augue nec molestie. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> <p>Duis a turpis sed lacus dapibus elementum sed eu lectus.</p> </div> ); } } export default Home
Stuff.jsreact-router
import React, { Component } from "react"; class Stuff extends React.Component { render() { return ( <div> <h2>STUFF</h2> <p>Mauris sem velit, vehicula eget sodales vitae, rhoncus eget sapien:</p> <ol> <li>Nulla pulvinar diam</li> <li>Facilisis bibendum</li> <li>Vestibulum vulputate</li> <li>Eget erat</li> <li>Id porttitor</li> </ol> </div> ); } } export default Stuff
Contact.jsapp
import React, { Component } from "react"; class Contact extends React.Component { render() { return ( <div> <h2>GOT QUESTIONS?</h2> <p>The easiest thing to do is post on our <a href="https://github.com/huangche007">GitHub</a>. </p> </div> ); } } export default Contact
在Main组件中已经有了这个App的基本框架,也有了Home、Stuff、Contact三个内容组件了,如今须要作的就是将它们链接起来构建成咱们的App,这时候就须要使用到了React 路由了,回到Main.js,确保导入的语句以下:框架
import React, { Component } from "react"; import { Route, NavLink, HashRouter } from "react-router-dom"; import Home from "./Home"; import Stuff from "./Stuff"; import Contact from "./Contact";
React路由工做方式被定义成一种称为路由区域,在路由区域里,有两件事可作:
导航的链接:在Main.js组件的render方法中增长<HashRouter>的代码:
class Main extends Component { render() { return ( <HashRouter> <div> <h1>Simple SPA</h1> <ul className="header"> <li><a href="/">Home</a></li> <li><a href="/stuff">Stuff</a></li> <li><a href="/contact">Contact</a></li> </ul> <div className="content"> </div> </div> </HashRouter> ); } }
HashRouter组件为导航和由路由组成的浏览器历史记录操做提供了基础,接下来将定义导航的链接,使用特殊的NavLink组件替换掉a标签,并为这样的组件添加to属性.
class Main extends Component { render() { return ( <HashRouter> <div> <h1>Simple SPA</h1> <ul className="header"> <li><NavLink to="/">Home</NavLink></li> <li><NavLink to="/stuff">Stuff</NavLink></li> <li><NavLink to="/contact">Contact</NavLink></li> </ul> <div className="content"> </div> </div> </HashRouter> ); } }
注意每一个链接,将让路由得知导航到的URL,URL的值(经过to属性定义)做为一个标识来确保正确的内容获得加载,咱们匹配内容的URL的方式在Route(路由)组件中获得使用
class Main extends Component { render() { return ( <HashRouter> <div> <h1>Simple SPA</h1> <ul className="header"> <li><NavLink to="/">Home</NavLink></li> <li><NavLink to="/stuff">Stuff</NavLink></li> <li><NavLink to="/contact">Contact</NavLink></li> </ul> <div className="content"> <Route path="/" component={Home}/> <Route path="/stuff" component={Stuff}/> <Route path="/contact" component={Contact}/> </div> </div> </HashRouter> ); } }
正如你所见到的,Route组件包含一个path属性,指定的path值决定了路由什么时候被激活。当路由激活的时候,经过组件prop指定的组件将被渲染。好比:当点击Stuff连接的时候,path值为/stuff的路由变成了激活状态,也就意味着Stuff组件的内容获得了渲染。
接下来能够npm start 来看看效果了。
当运行起来以后,会发现,不管咱们切换的Stuff,Contact,Home组件的内容一直存在,这意味着不管导航到哪一个路由,Home组件老是可以匹配上,这是不对的。能够在Home路由组件中,增长exact属性来解决。
<div className="content"> <Route exact path="/" component={Home}/> <Route path="/stuff" component={Stuff}/> <Route path="/contact" component={Contact}/> </div>
exact属性可以确保只有路由路径正确的匹配,那么这个路由组件才能将加载