React Router v4简介及其对路由的哲学

React Router v4 introduces a new dynamic, component based approach to routing.

React Router v4引入了一种新的基于组件的动态,动态路由方法。

In this post, we’ll talk about the philosophies behind React Router and give an introduction to the syntax by breaking down the “Basic” example on the React Router docs.

在本文中,我们将讨论React Router背后的原理,并通过分解React Router文档上的“ Basic”示例来对该语法进行介绍。

Note that this article just one part of my comprehensive new React Router course.

请注意,本文只是我全面的新React Router课程的一部分

Also, I’ve created a video to go with this article:

另外,我还创建了一个视频,以配合本文:

If you’ve been in React land for the last few years, you may have noticed that React Router has gone through a few different iterations. The React Router we have today (v4) is a huge improvement on previous versions.

如果您最近几年来过React领域,您可能已经注意到React Router经历了几次不同的迭代。 我们今天(v4)的React Router是对以前版本的巨大改进。

The reason for these changes are pretty standard — the authors today are more experienced React developers than they were when React Router was first built. You see, back in 2014, everyone was new to React. React itself was still under a year old and no one really knew to what extent this whole component thing would play out.

这些更改的原因很标准–与最初构建React Router时相比,今天的作者是经验更丰富的React开发人员。 您会发现,在2014年, 每个人都是React的新手。 React本身还不到一岁,没有人真正知道这整个组件将在多大程度上发挥作用。

With that in mind, it’s natural that the first commits of React Router looked something like this:

考虑到这一点,React Router的第一次提交看起来自然是这样的:

At the time, both Michael and Ryan (the creators of React Router) were coming from Ember backgrounds. So naturally, the first version of React Router was similar in nature to that of Ember’s router. That is, with both routers you’d establish your routes statically as part of the app’s initialization process.

当时,Michael和Ryan(React Router的创建者)都来自Ember背景。 因此,第一个版本的React Router本质上与Ember的路由器相似。 也就是说,使用这两个路由器,您将在应用程序初始化过程中静态地建立路由。

In fact, mostly all of the router’s you’re probably familiar with are used this way — Express, Angular, Ember. Even React Router pre version 4 used static routes as well. Here’s some code from React Router before version 4.

实际上,大多数您可能熟悉的路由器都是以这种方式使用的-Express,Angular,Ember。 甚至React Router 4之前的版本也使用静态路由。 这是版本4之前的React Router的一些代码。

Typically you’d have a routes.js file where you’d establish your static routes.

通常,您会有一个routes.js文件,用于在其中建立静态路由。

// routes.js
const routes = (  <Router>    <Route path='/' component={Main}>      <IndexRoute component={Home} />      <Route path='playerOne' component={Prompt} />      <Route path='playerTwo/:playerOne' component={Prompt} />      <Route path='battle' component={ConfirmBattle} />      <Route path='results' component={Results} />      <Route onEnter={checkAuth} path='dashboard' component={Dashboard} />    </Route>  </Router>)
export default routes

Then, when you’d initialize your app, you’d import your routes and render them.

然后,在初始化应用程序时,您将导入路线并进行渲染。

// index.js
import React from 'react'import ReactDOM from 'react-dom'import routes from './config/routes'
ReactDOM.render(routes, document.getElementById('app'))

This brings up the question: “is static routing bad?”

这就提出了一个问题:“静态路由不好吗?”

While the answer to that is definitely “no” one could still argue that it’s not really the “React way” of doing things though.

尽管对此的答案肯定是“否”,但人们仍然可以说,这实际上并不是做事的“React方式”。

Since its creation, not only have the creators of React Router become more experienced in the intricacies of building a router, but they’ve naturally also gained more experience with React itself, so much so their full time jobs are to teach it. What they found during their workshops was that the principles they taught about React, like component composition, didn’t align with the actual API of React Router. Not only that, but in some places they were actually competing with the React API. Looking back at the previous example, we pass an onEnter prop to the <Route> component.

自创建以来,不仅使React Router的创建者在构建路由器的复杂性方面变得更有经验,而且他们自然也获得了更多有关React本身的经验,所以他们全职工作就是要教它。 他们在研讨会上发现的是,他们教授的有关React的原理(如组件组成)与React Router的实际API不符。 不仅如此,在某些地方,他们实际上还在与React API竞争。 回顾前面的示例,我们将一个onEnter传递给<Rou te>组件。

<Route onEnter={checkAuth} path='dashboard' component={Dashboard} />

The idea here is that before the user sees the Dashboard component, the checkAuth function verifies the user is authenticated. Well, doesn’t that sound similar to what should happen inside of Dashboard’s componentDidMount lifecycle hook? It is.

这里的想法是,在用户看到Dashboard组件之前, checkAuth函数会验证用户是否已通过身份验证。 好吧,这听起来不像DashboardcomponentDidMount生命周期挂钩内部应该发生的事情吗? 它是。

With previous versions of React Router, it was more of a router for React than an actual React router. React Router v4 was built fix these inconsistencies and work with React, rather than against it. If you’re already familiar with the benefits of React and the benefits of component composition, React Router v4 is going to make you feel at home — you just need to forget everything you know about traditional static routers.

在早期版本的React Router中,它比实际的React路由器更多地是用于React的路由器。 React Router v4是为解决这些不一致之处而构建的,可以与React一起使用,而不是针对它。 如果您已经熟悉React的好处和组件组成的好处,那么React Router v4将带给您宾至如归的感觉-您只需要忘记关于传统静态路由器的所有知识即可。

Now the question is why is it that React Router v4 aligns nicely with React when previous versions fought against it? The answer is because it ditched static routing in favor of dynamic routing and the entire API is just components. What that means is that you declare your routes as part of your application just like you would any other component.

现在的问题是,为什么早期版本的React Router v4与React很好地匹配? 答案是因为它放弃了静态路由,转而使用动态路由,并且整个API只是组件。 这意味着您像其他任何组件一样,将路由声明为应用程序的一部分。

Let’s take a look at some code.

让我们看一些代码。

The goal here is to start out with some very basic code, then slowly add routing functionality to it. Here’s our starting code.

这里的目标是从一些非常基本的代码开始,然后向其中缓慢添加路由功能。 这是我们的起始代码。

import React, { Component } from 'react'
class App extends Component {  render() {    return (      <div>        React Rotuer Course      </div>    )  }}
export default App

As I mentioned earlier, React Router v4 is “just components.” So the first thing we’ll need to do is import the ones we’ll need.

正如我之前提到的,React Router v4只是“组件”。 因此,我们需要做的第一件事就是导入我们需要的东西。

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

A few things to note here. First, we’re importing BrowserRouter and renaming it Router. That’s not necessary, but it’s pretty common. What BrowserRouter does is it allows React Router to pass the app’s routing information down to any child component it needs (via context). So to make React Router work, you’ll need to render BrowserRouter at the root of your application.

这里需要注意的几件事。 首先,我们要导入BrowserRouter并将其重命名为Router 。 这不是必需的,但很普遍。 BrowserRouter作用是允许React Router将应用程序的路由信息​​向下传递到所需的任何子组件(通过上下文)。 因此,要使React Router正常工作,您需要在应用程序的根目录下呈现BrowserRouter

import React, { Component } from 'react'import {  BrowserRouter as Router,  Route,  Link,} from 'react-router-dom'
class App extends Component {  render() {    return (      <Router>        <div>          React Rotuer Course        </div>      </Router>    )  }}
export default App

Next we have Route. Route is both the backbone and the genius behind React Router v4. When the app’s location matches a certain path, Route will render a specified component, when it doesn’t, it will render null. So say for example we had a Home component that we wanted to render when our app was at the index path /. Our code would look something like this:

接下来,我们有RouteRoute是React Router v4的骨干力量和天才。 当应用程序的位置与特定路径匹配时, Route将呈现指定的组件,否则,它将呈现null。 举例来说,假设我们有一个Home组件,当我们的应用程序位于索引路径/时,我们想渲染该组件。 我们的代码如下所示:

import React, { Component } from 'react'import {  BrowserRouter as Router,  Route,  Link,} from 'react-router-dom'
const Home = () => (  <h2>Home</h2>)
class App extends Component {  render() {    return (      <Router>        <div>          <Route path='/' component={Home} />        </div>      </Router>    )  }}
export default App

With the code above, if were were at the index page (/), we would see the Home component. If we weren’t, we wouldn’t see anything (because Route would have rendered null).

使用上面的代码,如果位于索引页(/),我们将看到Home组件。 如果不是的话,我们什么也看不到(因为Route会变成null)。

Let’s add a few more routes now.

现在让我们添加更多路线。

import React, { Component } from 'react'import {  BrowserRouter as Router,  Route,  Link,} from 'react-router-dom'
const Home = () => (  <div>    <h2>Home</h2>  </div>)
const About = () => (  <div>    <h2>About</h2>  </div>)
const Topics = () => (  <div>    <h2>Topics</h2>  </div>)
class App extends Component {  render() {    return (      <Router>        <div>          <Route path='/' component={Home} />          <Route path='/about' component={About} />          <Route path='/topics' component={Topics} />        </div>      </Router>    )  }}
export default App

Notice that if we want to add more routes to our app, we just render more Route components. Again, this may feel a little weird to your brain if you’re coming from static based routers since we’re literally rendering our routes.

请注意,如果我们想向我们的应用添加更多路线,我们只需渲染更多Route组件。 同样,如果您来自基于静态的路由器,这可能会让您的大脑有些奇怪,因为我们实际上是在绘制路线。

One thing that helped me was to remember Route is just a normal React component with a render method. That render method is either rendering the component or it’s rendering null depending on if the path matches. So when we render multiple Route components like we’re doing above, those will either render the component or just render null.

帮助我的一件事是,记住Route只是一个带有render方法的普通React组件。 该render方法要么渲染组件,要么渲染null,这取决于路径是否匹配。 因此,当我们像上面那样渲染多个Route组件时,这些组件将渲染该组件或仅渲染null。

So far, so good. One caveat that you might not have seen from the above code is that right now if you run the app and you head to the /about path, you’ll notice that both the About component and the Home component are rendered. This is because even though / doesn’t match the location exactly, it’s still considered a partial match so the Home component is rendered. To get around this, you simply need to add an exact prop to the / Route to specify that you only want it to match when the location matches exactly.

到目前为止,一切都很好。 从上面的代码中可能看不到的一个警告是,如果现在运行应用程序并转到/about路径,则会注意到About组件和Home组件均已呈现。 这是因为即使/与位置不完全匹配,它仍被认为是部分匹配,因此呈现了Home组件。 为了解决这个问题,您只需要在/ Route中添加一个exact prop即可指定仅在位置完全匹配时才匹配它。

<Route exact path='/' component={Home} />

Now that we’re dynamically rendering UI based on the app’s location, the next thing we need to do is have some way for the user to change the apps location. This is where the Link component comes into play. It’s a simple component that allows the user to declaratively navigate around the app. Now, using Link, let’s add a simple navbar to our app.

现在,我们将根据应用程序的位置动态呈现UI,接下来我们需要做的就是让用户更改应用程序的位置。 这就是Link组件起作用的地方。 这是一个简单的组件,允许用户以声明方式浏览应用程序。 现在,使用Link ,向我们的应用程序添加一个简单的导航栏。

render() {  return (    <Router>      <div>        <ul>          <li><Link to='/'>Home</Link></li>          <li><Link to='/about'>About</Link></li>          <li><Link to='/topics'>Topics</Link></li>        </ul>
<Route path='/' component={Home} />        <Route path='/about' component={About} />        <Route path='/topics' component={Topics} />      </div>    </Router>  )}

At this point, we’ve covered the absolute fundamentals of React Router v4. We’re dynamically changing the UI based on the location by rendering a few different Route components and we’re able to change the location of our app by rendering a few different Link components.

至此,我们已经介绍了React Router v4的绝对基础。 我们通过渲染一些不同的Route组件来根据位置动态更改UI,并且能够通过渲染一些不同的Link组件来更改应用程序的位置。

Let’s go a little deeper and talk about nested routes. Nested routes were a fundamental aspect of previous versions of React Router and they continue to be today. The biggest difference is the way in which you go about creating nested routes now compared to previous versions of React Router. In previous, static versions, you’d just nest routes in your route config. Because React Router v4 is all about dynamic routing, you can’t do that. However, in my opinion, nested routes with React Router v4 is much more intuitive than with previous versions. Again, the key is to forget what you knew previously.

让我们更深入地讨论嵌套路由。 嵌套路由是以前版本的React Router的基本方面,并且一直延续到今天。 与以前版本的React Router相比,最大的区别是现在创建嵌套路由的方式。 在以前的静态版本中,您只是将路由嵌套在路由配置中。 因为React Router v4都是关于动态路由的,所以您不能这样做。 但是,我认为,React Router v4的嵌套路由比以前的版本直观得多。 同样,关键是忘记您以前所知道的。

Looking back at our example, what if we wanted the Topics component to render a nested navbar and some nested routes? The answer to that doesn’t need to be complicated. Just like you would nest a div, you can nest Routes.

回顾示例,如果我们希望Topics组件呈现嵌套的导航栏和一些嵌套的路线该怎么办? 答案不必太复杂。 就像嵌套div一样,您可以嵌套Route

const Topic = () => {  <div>    <h3>TOPIC</h3>  </div>}
const Topics = () => (  <div>    <h2>Topics</h2>    <ul>      <li>        <Link to={`/topics/rendering`}>          Rendering with React        </Link>      </li>      <li>        <Link to={`/topics/components`}>          Components        </Link>      </li>      <li>        <Link to={`/topics/props-v-state`}>          Props v. State        </Link>      </li>    </ul>
<Route path={`/topics/rendering`} component={Topic} />    <Route path={`/topics/components`} component={Topic} />    <Route path={`/topics/props-v-state`} component={Topic} />  </div>)

Now when the user navigates to /topics, they’ll see a nested navbar and the UI will be dynamically changing - just like before - based on the location. The only difference is now we’re rendering the navbar and the Routes inside of another component, which is also being rendered by React Router.

现在,当用户导航到/topics ,他们将看到一个嵌套的导航栏,并且UI将根据位置动态变化(就像以前一样)。 唯一的区别是现在我们在另一个组件内部渲染导航栏和Route ,这也由React Router渲染。

You may have noticed that we hard coded the URLs instead of dynamically creating them based on the current nested location we’re on. When React Router renders a component, it passes that component three things: match, location, and history. In this example, what we want is match.url which will give us the current matched portion of the URL (in our example, /topics). So anywhere where we’re hard coding /topic we can replace with match.url.

您可能已经注意到,我们对URL进行了硬编码,而不是根据当前所在的嵌套位置动态创建URL。 当React Router渲染一个组件时,它将向该组件传递三件事: matchlocationhistory 。 在此示例中,我们想要的是match.url ,它将为我们提供URL的当前匹配部分(在我们的示例中为/topics )。 因此,在任何我们要对/topic硬编码的地方,都可以用match.url代替。

const Topic = () => {  <div>    <h3>TOPIC</h3>  </div>}
const Topics = ({ match }) => (  <div>    <h2>Topics</h2>    <ul>      <li>        <Link to={`${match.url}/rendering`}>          Rendering with React        </Link>      </li>      <li>        <Link to={`${match.url}/components`}>          Components        </Link>      </li>      <li>        <Link to={`${match.url}/props-v-state`}>          Props v. State        </Link>      </li>    </ul>
<Route path={`${match.url}/rendering`} component={Topic} />    <Route path={`${match.url}/components`} component={Topic} />    <Route path={`${match.url}/props-v-state`} component={Topic} />  </div>)

Another thing you may have noticed is that we’re rendering three different Routes even though each are rendering the same component and the only difference is the nested URL. This is the perfect use case for using URL parameters.

您可能已经注意到的另一件事是,我们正在渲染三个不同的Route即使每个Routes都渲染相同的组件,唯一的区别是嵌套的URL。 这是使用URL参数的完美用例。

const Topics = ({ match }) => (  <div>    ...
<Route path={`${match.url}/:topicId`} component={Topic} />  </div>)

Now when React Router renders the Topic component, because we’re passed that match prop we talked about earlier, we’re also passed the topicId under match.params.

现在,当React Router渲染Topic组件时,因为我们已经传递了前面讨论过的match prop,所以我们还在topicId下传递了match.params

const Topic = ({ match }) => (  <div>    <h3>{match.params.topicId}</h3>  </div>)

Now lastly, when we’re at the /topics route, if a topic hasn’t already been selected, we want to render some text that says “Please select a topic”. We can make a component that renders that text or we can just use Routes render prop like so

现在,最后,当我们处于/topics路线时,如果尚未选择主题,则要渲染一些文字,表示“请选择一个主题”。 我们可以制作一个可以渲染文本的组件,也可以像这样使用Routerender道具

<Route   exact   path={match.url}   render={() => ( <h3>Please select a topic.</h3> )}/>

That’s it! Our final code now looks like this,

而已! 现在,我们的最终代码如下所示:

import React, { Component } from 'react'import {  BrowserRouter as Router,  Route,  Link} from 'react-router-dom'
const Home = () => (  <div>    <h2>Home</h2>  </div>)
const About = () => (  <div>    <h2>About</h2>  </div>)
const Topic = ({ match }) => (  <div>    <h3>{match.params.topicId}</h3>  </div>)
const Topics = ({ match }) => (  <div>    <h2>Topics</h2>    <ul>      <li>        <Link to={`${match.url}/rendering`}>          Rendering with React        </Link>      </li>      <li>        <Link to={`${match.url}/components`}>          Components        </Link>      </li>      <li>        <Link to={`${match.url}/props-v-state`}>          Props v. State        </Link>      </li>    </ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>    <Route exact path={match.url} render={() => (      <h3>Please select a topic.</h3>    )}/>  </div>)
class App extends Component {  render() {    return (      <Router>        <div>          <ul>            <li><Link to="/">Home</Link></li>            <li><Link to="/about">About</Link></li>            <li><Link to="/topics">Topics</Link></li>          </ul>
<hr/>
<Route exact path="/" component={Home}/>          <Route path="/about" component={About}/>          <Route path="/topics" component={Topics}/>        </div>      </Router>    )  }}
export default App

By utilizing a component based API, React Router v4 truly is a React router. I believe React will make you a better JavaScript developer and React Router v4 will make you a better React developer.

通过利用基于组件的API,React Router v4确实是一个React路由器。 我相信React将使您成为更好JavaScript开发人员,而React Router v4将使您成为更好的React开发人员。

Follow me on Twitter — @tylermcginnis. And check out more of my web development courses on TylerMcGinnis.com.

在Twitter上关注我- @tylermcginnis 。 并在TylerMcGinnis.com查看我的更多Web开发课程。

翻译自: https://www.freecodecamp.org/news/react-router-v4-philosophy-and-introduction-730fd4fff9bc/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值