React Router v4 版本学习指南
React Router v4 版本学习指南React Router 事实上是React官方的标准路由库。当你在一个多视图的React应用中来回切换,你需要一个路由来管理那些URL。React Router 专注于此,同步保持你应用的UI和URL。 这个教程主要给你介绍React Router 的v4版本,以及你使用它可以做的大部分事情。 开场白React 是一个很流行的库,用于在客户端渲染创建的单页应用(SPAs)。 一个SPA会有很多视图(也可以称为页面),不像传统的多页应用,视图之间的跳转不应该导致整个页面被重新加载。相反,我们希望视图就在当前页面里渲染。那些习惯于多页应用的最终用户,期望在一个SPA中应该包含以下特性:
路由跳转是指在同步保持浏览器URL的过程中渲染页面中的视图。React Router 让你声明式的操作路由跳转。声明式路由方法,通过说“路由应该是这样的”,允许你控制应用中的数据流: <Route path="/about" component={About}/>
你可以把 写在开头。有一个常见的误区,大家都认为React Router是由facebook官方开发的一个路由解决方案。实际上,它是一个因其设计和简易性而流行的第三方库。如果你的需求只局限于路由的跳转,你可以无需太多麻烦,就可以从头开始实现一个自定义的路由。但是,了解React Router的基础知识可以让你更清楚的认识一个路由是怎么工作的。 概述本次教程分为几个部分。首先,我们使用npm安装好React和React Router,然后我们就开始React Router的基础部分。你将会看到React Router不同的代码示例的效果。本次教程涉及的例子包含:
主要围绕构建这些路由所涉及的概念进行讨论。这个项目的全部代码在这个Github仓库可以看到。当你进入一个单独的demo目录,执行 让我们开始吧! 安装 React Router假设你已经有一个React开发环境并已经运行了。如果没有,可以跳转到React和JSX入门。或者,你可以使用Create React App来生成创建一个基本的React项目所需要的文件。这是Create React App生成的默认目录结构: react-routing-demo-v4
├── .gitignore
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── README.md
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ └── registerServiceWorker.js
└── yarn.lock
React Router库包含三个包: 使用npm安装 npm install --save react-router-dom
React Router 基础下面是路由的例子: <Router>
<Route exact path="/" component={Home}/>
<Route path="/category" component={Category}/>
<Route path="/login" component={Login}/>
<Route path="/products" component={Products}/>
</Router>
Router像上面的例子,你需要一个
它们之间主要的区别,可以在它们所创建的URL明显看出: // <BrowserRouter>
http://example.com/about
// <HashRouter>
http://example.com/#/about
使用 index.js/* Import statements */
import React from 'react';
import ReactDOM from 'react-dom';
/* App is the entry point to the React code.*/
import App from './App';
/* import BrowserRouter from 'react-router-dom' */
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,document.getElementById('root'));
注意:Router组件只能有一个子元素。子元素可以是HTML - 例如div - 也可以是一个react组件。 要让React Router工作,你需要从 上述代码给我们整个App组件创建了一个history实例。接下来正式介绍下history。 history
每个router组件创建了一个history对象,用来记录当前路径( 接下来,我们谈谈Links和Routes Links and Routes
另一方面, 我们已经介绍了创建一个基本的路由需要的所有东西。让我们试一个吧。 Demo 1: 基础路由src/App.js/* Import statements */
import React,{ Component } from 'react';
import { Link,Route,Switch } from 'react-router-dom';
/* Home component */
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
/* Category component */
const Category = () => (
<div>
<h2>Category</h2>
</div>
)
/* Products component */
const Products = () => (
<div>
<h2>Products</h2>
</div>
)
/* App component */
class App extends React.Component {
render() {
return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
/* Link components are used for linking to other views */
<li><Link to="/">Homes</Link></li>
<li><Link to="/category">Category</Link></li>
<li><Link to="/products">Products</Link></li>
</ul>
</nav>
/* Route components are rendered if the path prop matches the current URL */
<Route path="/" component={Home}/>
<Route path="/category" component={Category}/>
<Route path="/products" component={Products}/>
</div>
)
}
}
我们在 在App组件中,我们写了路由跳转的逻辑。 在这里, <Route exact={true} path="/" component={Home}/>
若只想要路由在路径完全相同时渲染,你就可以使用 嵌套路由创建嵌套路由之前,我们需要更深入的理解
Path and matchpath用来标识路由匹配的URL部分。React Router使用了Path-to-RegExp库将路径字符串转为正则表达式。然后正则表达式会匹配当前路径。 当路由路径和当前路径成功匹配,会生成一个对象,我们叫它match。match对象有更多关于URL和path的信息。这些信息可以通过它的属性获取,如下所示:
现在我们完全了解了 Switch组件在我们开始示例代码签,我想给你介绍下 <Route exact path="/" component={Home}/>
<Route path="/products" component={Products}/>
<Route path="/category" component={Category}/>
<Route path="/:id" render = {()=> (<p> I want this text to show up for all routes other than '/','/products' and '/category' </p>)}/>
当URL为 Demo 2: 嵌套路由之前,我们给 src/App.jsimport React,Switch } from 'react-router-dom';
import Category from './Category';
class App extends Component {
render() {
return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
<li><Link to="/">Homes</Link></li>
<li><Link to="/category">Category</Link></li>
<li><Link to="/products">Products</Link></li>
</ul>
</nav>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/category" component={Category}/>
<Route path="/products" component={Products}/>
</Switch>
</div>
);
}
}
export default App;
/* Code for Home and Products component omitted for brevity */
不像React Router之前的版本,在版本4中,嵌套的 src/Category.jsximport React from 'react';
import { Link,Route } from 'react-router-dom';
const Category = ({ match }) => {
return( <div> <ul>
<li><Link to={`${match.url}/shoes`}>Shoes</Link></li>
<li><Link to={`${match.url}/boots`}>Boots</Link></li>
<li><Link to={`${match.url}/footwear`}>Footwear</Link></li>
</ul>
<Route path={`${match.path}/:name`} render= {({match}) =>( <div> <h3> {match.params.name} </h3></div>)}/>
</div>)
}
export default Category;
首先,我们给嵌套路由定义了一些Link。之前提到过, <Route path={`${match.path}/:name`} render= {({match}) =>( <div> <h3> {match.params.name} </h3></div>)}/>
这是我们首次尝试动态路由。不同于硬编码路由,我们给pathname使用了变量。 { name: 'running-shoes' }
参数可以通过 Demo 3: 带Path参数的嵌套路由我们让事情变得再复杂一些,可以吗?一个真实的路由应该是根据数据,然后动态展示。假设我们获取了从服务端API返回的product数据,如下所示。 src/Products.jsxconst productData = [
{
id: 1,name: 'NIKE Liteforce Blue Sneakers',description: 'Lorem ipsum dolor sit amet,consectetur adipiscing elit. Proin molestie.',status: 'Available'
},{
id: 2,name: 'Stylised Flip Flops and Slippers',description: 'Mauris finibus,massa eu tempor volutpat,magna dolor euismod dolor.',status: 'Out of Stock'
},{
id: 3,name: 'ADIDAS Adispree Running Shoes',description: 'Maecenas condimentum porttitor auctor. Maecenas viverra fringilla felis,eu pretium.',status: 'Available'
},{
id: 4,name: 'ADIDAS Mid Sneakers',description: 'Ut hendrerit venenatis lacus,vel lacinia ipsum fermentum vel. Cras.',status: 'Out of Stock'
},];
我们需要根据下面这些路径创建路由:
src/Products.jsx/* Import statements have been left out for code brevity */
const Products = ({ match }) => {
const productsData = [
{
id: 1,name: 'NIKE Liteforce Blue Sneakers',description: 'Lorem ipsum dolor sit amet,status: 'Available'
},//Rest of the data has been left out for code brevity
];
/* Create an array of `<li>` items for each product
var linkList = productsData.map( (product) => { return( <li> <Link to={`${match.url}/${product.id}`}> {product.name} </Link> </li> ) }) return( <div> <div> <div> <h3> Products</h3> <ul> {linkList} </ul> </div> </div> <Route path={`${match.url}/:productId`} render={ (props) => <Product data= {productsData} {...props} />}/> <Route exact path={match.url} render={() => ( <div>Please select a product.</div> )} /> </div> ) }
首先,我们通过 <Route path={`${match.url}/:productId`}
render={ (props) => <Product data= {productsData} {...props} />}/>
你可能期望使用 这是Product组件的代码。 src/Product.jsx/* Import statements have been left out for code brevity */
const Product = ({match,data}) => {
var product= data.find(p => p.id == match.params.productId);
var productData;
if(product)
productData = <div>
<h3> {product.name} </h3>
<p>{product.description}</p>
<hr/>
<h4>{product.status}</h4> </div>;
else
productData = <h2> Sorry. Product doesnt exist </h2>;
return (
<div>
<div>
{productData}
</div>
</div>
)
}
保护式路由最后一个demo,我们将围绕保护式路由的技术进行讨论。那么,如果有人想进入 重定向类似服务端重定向, `<Redirect to={{pathname: '/login',state: {from: props.location}}}`
如果有人已经注销了账户,想进入 自定义路由自定义路由最适合描述组件里嵌套的路由。如果我们需要确定一个路由是否应该渲染,最好的方法是写个自定义组件。下面是通过其他路由来定义自定义路由。 src/App.js/* Add the PrivateRoute component to the existing Routes */
<Switch>
<Route exact path="/" component={Home} data={data}/>
<Route path="/category" component={Category}/>
<Route path="/login" component={Login}/>
<PrivateRoute authed={fakeAuth.isAuthenticated} path='/products' component = {Products} />
</Switch>
若用户已登录, 这是PrivateRoute的定义。 src/App.js/* PrivateRoute component definition */
const PrivateRoute = ({component: Component,authed,...rest}) => {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login',state: {from: props.location}}} />} />
)
}
如果用户已登录,路由将渲染Admin组件。否则,用户将重定义到 最后,下面是Login组件的代码: src/Login.jsximport React from 'react';
import { Redirect } from 'react-router-dom';
class Login extends React.Component {
constructor() {
super();
this.state = {
redirectToReferrer: false
}
// binding 'this'
this.login = this.login.bind(this);
}
login() {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true })
})
}
render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state;
if (redirectToReferrer) {
return (
<Redirect to={from} />
)
}
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
/* A fake authentication function */
export const fakeAuth = {
isAuthenticated: false,authenticate(cb) {
this.isAuthenticated = true
setTimeout(cb,100)
},}
下面这行是对象的解构赋值的示例,es6的特性之一。 `const { from } = this.props.location.state || { from: { pathname: '/' } }`
让我们把所有片段拼凑到一块,好吗?这是我们使用React Router创建的应用最终效果: Demo 4: 保护式路由点击此查看在线demo 总结如你在本文中所看到的,React Router是一个帮助React构建更完美,更声明式的路由库。不像React Router之前的版本,在v4中,一切就“只是组件”。而且,新的设计模式也更完美的使用React的构建方式来实现。 在本次教程中,我们学到了:
最后,我们还学习了一些高级路由技巧,用来创建保护式路由的最终demo。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |