如何构建自己的React Router v4

I still remember the feelings when I first started learning about routing in client side applications. At the time I was just a wee lad still getting my feet wet with this whole “Single Page Application” thing and I’d be lying if I said it didn’t take a poop all over my brain. From the beginning it’s as if my brain treated my application code and my router code as two unique and distinct ideas. They were like step brothers who didn’t like each other but were forced to live together anyway.

我仍然记得当我第一次开始学习客户端应用程序中的路由时的感受。 那时我还只是个小家伙,还用这整个“单页应用程序”弄湿了我的脚,如果我说这不会让我大吃一惊,那我会说谎。 从一开始,就好像我的大脑将我的应用程序代码和路由器代码视为两个独特而独特的想法。 他们就像继兄弟,他们彼此不喜欢,但还是被迫生活在一起。

Over the last few years I have, probably at this point against your approval, been fortunate enough to be able to teach this idea of routing to other developers. Unfortunately, it turns out that most of our brains seem to be wired similarly to mine. I think there’s a few reasons for this. First, routing in general is pretty complex. This makes, for those library authors, finding the right abstraction over routing even more complex. Second, because of this complexity, consumers of routing libraries tend to blindly trust the abstraction without really understanding what’s going on under the hood.

在过去的几年中,可能是在这一点上,尽管您未得到您的认可,我还是很幸运的能够将这种路由选择的思想传授给其他开发人员。 不幸的是,事实证明,我们的大多数大脑似乎与我的大脑相似。 我认为有几个原因。 首先,一般来说,路由非常复杂。 对于那些库作者来说,这使寻找路由的正确抽象变得更加复杂。 其次,由于这种复杂性,路由库的使用者趋向于盲目地信任抽象而不真正了解底层的情况。

In this tutorial, we’ll dive into solving both problems. First the later by recreating our own simplified version of React Router v4 which will then shed some light on the former, that is, whether or not RRv4 is a reasonable abstraction.

在本教程中,我们将致力于解决这两个问题。 首先,通过重新创建我们自己的简化版本的React Router v4,后者将为后者提供一些启发,即RRv4是否是合理的抽象。

Here’s our app code we’ll be using to test our ~React Router implementation once we’ve built it. You can play around with the final example here

这是我们的应用程序代码,构建后将用于测试〜React Router实现。 您可以在此处尝试最后一个示例

const Home = () => (  

Home

)
const About = () => (  

About

)
const Topic = ({ topicId }) => (  

{topicId}

)
const Topics = ({ match }) => {  const items = [    { name: 'Rendering with React', slug: 'rendering' },    { name: 'Components', slug: 'components' },    { name: 'Props v. State', slug: 'props-v-state' },  ]
return (    

Topics

    {items.map(({ name, slug }) => (
  • {name}
  • ))}
{items.map(({ name, slug }) => ( ( )} /> ))} (

Please select a topic.

)}/>
)}
const App = () => (  
  • Home
  • About
  • Topics

          
)

If you’re unfamiliar with React Router v4, here’s the basic premise. Routes render some UI when a URL matches a location you specify in the Route’s path prop. Links provide a declarative, accessible way to navigate around your app. In other words, the Link component allows you to update the URL, and the Route component changes your UI based on that new URL. The focus of this tutorial isn’t actually on teaching the basics of RRV4, so if the code above is still confusing, head over to the official docs, play around with the examples, and once you’re more comfortable, come back.

如果您不熟悉React Router v4,这是基本前提。 当URL与您在Route的path属性中指定的位置匹配时, Route呈现一些UI。 Link提供了一种声明式,可访问的方法来浏览您的应用程序。 换句话说,“ Link组件允许您更新URL,而“ Route组件则根据该新URL来更改UI。 本教程的重点实际上并不是讲授RRV4的基础知识,因此,如果上面的代码仍然令人困惑,请转到官方文档 ,尝试使用示例,一旦您感到舒适,再回来。

The first thing you should notice is that we’ve introduced two components that were given to us by the router into our app, Link and Route. My favorite aspect of React Router v4 is that the API is “Just Components™”. What this means is that if you’re already familiar with React, the same intuition you have about components and how to compose them, will continue to hold true in regards to your routing code. And even more convenient for our use case here, because we’re already familiar with how to create components, creating our own React Router will be nothing more than doing what we’re already familiar with, creating more components.

您应该注意的第一件事是,我们将路由器提供的两个组件引入了我们的应用程序LinkRoute 。 我最喜欢的React Router v4方面是API是“ Just Components™”。 这意味着,如果您已经熟悉React,关于组件以及如何组成它们的直觉将继续适用于您的路由代码。 对于我们这里的用例来说,甚至更加方便,因为我们已经熟悉如何创建组件,因此创建自己的React Router只不过是做我们已经熟悉的事情,创建更多组件。

We’re going to start off by creating our Route component. Before we dive into the code, let’s go ahead and check out the API (which conveniently is just which props it takes).

我们将从创建Route组件开始。 在深入研究代码之前,让我们继续检查一下API(方便地查看它所需要的道具)。

In our example above, you’ll notice that te> can take in three props. exact, path, and component. This means the propTypes for our Route component currently look like this,

在上面的示例中,您会注意到 te>可以接受三个rops. e xact ,path , and com组件。 这意味着s the pro pTypes FO r our路线组件目前这个样子,

static propTypes = {  exact: PropTypes.bool,  path: PropTypes.string,  component: PropTypes.func,}

There’s a few subtleties here. First, the reason path isn’t required is because if a Route isn’t given a path, it will automatically be rendered. Second, the reason component isn’t marked as required either is because there are actually a few different ways to tell React Router the UI you want to render if the path matches. One way that isn’t in our example above is with the render prop. It looks like this,

这里有一些微妙之处。 首先,之所以path不是必需的,因为如果Route没有给出一个路径,它会自动呈现。 其次,之所以没有将该component标记为必需component ,是因为实际上有几种不同的方法可以在路径匹配时告诉React Router您要呈现的UI。 上面的示例中没有的一种方法是使用render道具。 看起来像这样

 {  return }} />

render allows you to conveniently inline a function which returns some UI rather than creating a separate component. So we’ll add that to our propTypes as well,

render使您可以方便地内联返回一个UI的函数,而无需创建单独的组件。 因此,我们也将其添加到propTypes中,

static propTypes = {  exact: PropTypes.bool,  path: PropTypes.string,  component: PropTypes.func,  render: PropTypes.func,}

Now we know what props Route receives, let’s talk again about what it actually does. Route “renders some UI when the URL matches a location you specify in the Route’s path prop”. Based off of that definition, we know that te> is going to need some functionality which checks if the current URL matches the component’s path prop. If it does, we’ll render some UI. If it doesn’t, we’ll do nothing by returning null.

现在我们知道Route收到了什么道具,让我们再说一说它实际上是做什么的。 路由“ URL与您在路由的path属性中指定的位置匹配时,提供一些UI”。 根据该定义的了,我们知道, 德>是要需要一些如果当前的URL匹配COMPON其检查功能ent'小号路径道具。 如果是这样,我们将渲染一些UI。 如果不是,则返回null将不执行任何操作。

Let’s see what this looks like in code, trusting that we’ll build out the matching function, which we’ll call matchPath, later.

让我们看看代码中的内容,相信我们将构建匹配函数,稍后将其称为matchPath

class Route extends Component {  static propTypes = {    exact: PropTypes.bool,    path: PropTypes.string,    component: PropTypes.func,    render: PropTypes.func,  }
render () {    const {      path,      exact,      component,      render,    } = this.props
const match = matchPath(      location.pathname, // global DOM variable      { path, exact }    )
if (!match) {      // Do nothing because the current      // location doesn't match the path prop.
return null    }
if (component) {      // The component prop takes precedent over the      // render method. If the current location matches      // the path prop, create a new element passing in      // match as the prop.
return React.createElement(component, { match })    }
if (render) {      // If there's a match but component      // was undefined, invoke the render      // prop passing in match as an argument.
return render({ match })    }
return null  }}

Now Route is looking pretty solid. If the current location matches the path prop that was passed in, we render some UI, if not, we don’t do anything.

现在, Route看起来很稳定。 如果当前位置与传入的path道具匹配,我们将渲染一些UI,否则,我们将不执行任何操作。

Let’s take a step back for a moment and talk about routing in general. In a client side application, there are really only two ways for the user to update the URL. The first way is clicking on an anchor tag and the second is by clicking the back/forward button. Foundationally, our router needs to be aware of the current URL and render UI based on it. What this also means is that our router needs to be aware of when the URL changes, so that it can figure out which new UI to display based on that new URL. If we know that the only way to update a URL is through an anchor tag or the forward/back button, we can plan for and react to those changes. We’ll get into anchor tags a little later when we build out our nk> component, but for now, I want to focus on the back/forward buttons. React Router uses History’s .listen method to listen to changes for the current URL, but to avoid bringing in another library, we’ll use HTML5’s popstate event. popstate, which will be fired whenever the user clicks on the forward or back button, is exactly what we need. Because it’s the Routes that are rendering the UI based off the current URL, it makes sense to also give Routes the ability to listen for and re-render whenever a popstate event occurs. By re-rendering, each Route will re-check to see if they match with the new URL. If they do, they’ll render UI, if not, they’ll do nothing. Let’s see what this looks like now,

让我们退后一会儿,大致讨论一下路由。 在客户端应用程序中,用户实际上只有两种更新URL的方法。 第一种方法是单击锚标记,第二种方法是单击后退/前进按钮。 从根本上说,我们的路由器需要知道当前的URL并基于该URL呈现UI。 这也意味着我们的路由器需要知道URL何时更改,以便可以根据该新URL找出要显示的新UI。 如果我们知道更新URL的唯一方法是通过定位标记或前进/后退按钮,我们可以计划并做出React。 稍后,当我们构建 nk>组件时,我们将使用锚标记,但是现在,我要集中讨论后退/前进按钮。 React Router 使用 ory's . 使用listen方法侦听当前URL的更改,但为避免引入另一个库,我们将使用HT ML5's po寄存器vent. po vent. po pstate,这将被解雇时的前进或后退按钮,用户点击,这正是我们需要的。 因为它是s the正在呈现基于关闭当前URL的UI路线,是有意义的也give路由监听的能力和whene重新渲染ver a po pstate事件发生。 通过重新渲染, each路由将重新检查以查看它们是否与新URL匹配。 如果这样做,则将呈现UI;否则,它们将不执行任何操作。 让我们看看现在的样子,

class Route extends Component {  static propTypes: {    path: PropTypes.string,    exact: PropTypes.bool,    component: PropTypes.func,    render: PropTypes.func,  }
componentWillMount() {    addEventListener("popstate", this.handlePop)  }
componentWillUnmount() {    removeEventListener("popstate", this.handlePop)  }
handlePop = () => {    this.forceUpdate()  }
render() {    const {      path,      exact,      component,      render,    } = this.props
const match = matchPath(location.pathname, { path, exact })
if (!match)      return null
if (component)      return React.createElement(component, { match })
if (render)      return render({ match })
return null  }}

You should notice that all we’ve done is add a popstate listener when the component mounts, and when the popstate event is fired, we call forceUpdate which will kick off a re-render.

您应该注意到,我们所做的只是在装入组件时添加了一个popstate侦听器,并且在触发popstate事件时,我们调用forceUpdate来启动重新渲染。

Now, no matter how many te>s we’re rendering, each of them will listen for, re-match, and re-render based on the forward/back buttons.

现在,无论我们渲染多少 te>,它们中的每一个都将基于前进/后退按钮监听,重新匹配和重新渲染。

One thing we’ve been “hand waving” over up until this point has been our matchPath function. This function is pivotal to our router because it’s the function which is going to decide if a current URL matches the path of a te> component as we talked about above. One nuance to matchPath is we need to make sure that we take into account <Route>s exact prop. If you’re not familiar with what exact does, here’s an explanation straight from the docs

到目前为止,我们一直在“挥手”做一件事,就是我们的matchPath函数。 该功能对我们的路由器至关重要,因为如前所述,该功能将决定当前URL是否与 te>组件的路径匹配。 一个暖ce to mat chPath是我们需要确保我们考虑到AC count & LT ;Rout E>确切概率道具。 如果你不福美来r wit ^ h什么确切的那样,这里是一个解释从文档直

When true, will only match if the path matches the location.pathname exactly.

如果为true ,则仅在路径与location.pathname完全匹配时才匹配

Now, let’s dive into the implementation of our matchPath function. If you look back at our Route component, you’ll see that the signature for matchPatch looks like this,

现在,让我们matchPath函数的实现。 如果您回顾一下我们的Route组件,您将看到matchPatch的签名如下所示,

const match = matchPath(location.pathname, { path, exact })

Where match is either an object or null depending on if there was a match. Based on that signature, we can build out the first part of matchPath like this,

match是对象还是null,具体取决于是否存在匹配项。 基于该签名,我们可以像这样构建matchPath的第一部分,

const matchPatch = (pathname, options) => {  const { exact = false, path } = options}

Here we’re using some ES6 magic. We’re saying “create a variable called exact which equates to options.exact, unless that’s undefined, then set it to false. Also create a variable called path which eqautes to options.path”.

在这里,我们使用一些ES6魔术。 我们说的是“创建一个名为peract的变量,它等同于options.exact,除非未定义,然后将其设置为false。 还创建一个名为path的变量,它等同于options.path”。

Earlier I mentioned “the reason path isn’t required is because if a Route isn’t given a path, it will automatically be rendered”. Well since it’s indirectly our matchPath function which decides if something is rendered or not (by whether there’s a match), let’s add that functionality now.

前面我提到“不需要path的原因是,如果未给Route给出路径,它将自动呈现”。 好吧,因为这是间接地由我们的matchPath函数来决定是否呈现某些内容(通过是否存在匹配项),所以现在添加该功能。

const matchPatch = (pathname, options) => {  const { exact = false, path } = options
if (!path) {    return {      path: null,      url: pathname,      isExact: true,    }  }}

Now comes the matching part. React Router uses pathToRegex for this, we’ll simplify things and just use a simple Regex.

现在是匹配部分。 React Router为此使用pathToRegex ,我们将简化事情,仅使用一个简单的Regex。

const matchPatch = (pathname, options) => {  const { exact = false, path } = options
if (!path) {    return {      path: null,      url: pathname,      isExact: true,    }  }
const match = new RegExp(`^${path}`).exec(pathname)
}

If you’re not familiar with .exec, it’s going to return an array containing the matched text if it finds a match, otherwise it returns null.

如果您不熟悉.exec ,它将在找到匹配项时返回包含匹配文本的数组,否则返回null。

Here is every match when our example app routes to `/topics/components

这是我们的示例应用程序路由到`/ topics / components时的所有match

Notice that we’re getting a match for every te> that’s in our app. That’s because, well, each <Route> calls matchPath in its render method.

请注意,我们正在为应用程序match的每个 te> match 那是因为, each & e> cal ls matchPath在其reder方法中。

Now that we know what the match that .exec is returning, all we need to do now is figure out if there’s a match.

既然我们知道.exec返回的match .exec是什么,那么现在我们需要确定是否存在匹配项。

const matchPatch = (pathname, options) => {  const { exact = false, path } = options
if (!path) {    return {      path: null,      url: pathname,      isExact: true,    }  }
const match = new RegExp(`^${path}`).exec(pathname)
if (!match) {    // There wasn't a match.    return null  }
const url = match[0]  const isExact = pathname === url
if (exact && !isExact) {    // There was a match, but it wasn't    // an exact match as specified by    // the exact prop.
return null  }
return {    path,    url,    isExact,  }}

Earlier I mentioned how there’s really just two ways to update the URL if you’re the user, via the back/forward buttons, or clicking on an achor tag. We’ve taken care of re-rendering on back/forward clicks via the popstate event listener in our Route, now let’s take care of the anchor tag by building our our Link component.

前面我提到过,如果您是用户,实际上只有两种方法可以通过后退/前进按钮或单击achor标签来更新URL。 我们已经通过Routepopstate事件侦听器对后退/前进点击进行了重新渲染,现在我们通过构建我们的Link组件来处理定位标记。

The API for Link looks like this,

Link API看起来像这样,

Where to is a string and is the location to link to and replace is a boolean which when true, clicking the link will replace the current entry in the history stack instead of adding a new one.

其中to是一个字符串,是链接和replace的位置的布尔值,当为true时,单击链接将替换历史记录堆栈中的当前条目,而不是添加新条目。

Adding those propTypes to our Link component, we get this,

将这些propTypes添加到我们的Link组件中,我们得到了这一点,

class Link extends Component {  static propTypes = {    to: PropTypes.string.isRequired,    replace: PropTypes.bool,  }}

Now we know that the render method in our Link component needs to return an anchor tag, but we obviously don’t want to cause a full page refresh every time we switch routes, so we’ll hijack the anchor tag by adding a onClick handler to it

现在我们知道Link组件中的render方法需要返回一个定位标记,但是显然我们不想每次切换路线时都刷新整个页面,因此我们将通过添加onClick处理程序来劫持定位标记对此

class Link extends Component {  static propTypes = {    to: PropTypes.string.isRequired,    replace: PropTypes.bool,  }
handleClick = (event) => {    const { replace, to } = this.props    event.preventDefault()
// route here.  }
render() {    const { to, children} = this.props
return (              {children}          )  }}

Now all that’s lacking is actually changing the current location. To do this React Router uses History’s push and replace methods, but we’ll use HTML5’s pushState and replaceState methods to avoid adding in a dependency.

现在所缺少的实际上是更改当前位置。 为此,React Router使用History的pushreplace方法,但是我们将使用HTML5的pushState和replaceState方法来避免添加依赖项。

We’re hand waving over the History library in this post as a way to avoid external dependencies but it’s crucial for the real React Router code as it normalizes the differences in managing session history in various browser environments.

我们在这篇文章中介绍了History库,以避免外部依赖,但这对真正的React Router代码至关重要,因为它规范了在各种浏览器环境中管理会话历史记录的差异。

Both pushState and replaceState take in three arguments. The first is an object which is associated with the new history entry - we don’t need this functionality so we’ll just pass in an empty object. The second is a title, which we also don’t need so we’ll pass in null. The third, and the one we’ll actually use, is a relative URL.

pushStatereplaceState接受三个参数。 第一个是与新历史记录条目相关联的对象-我们不需要此功能,因此我们只传递一个空对象。 第二个是标题,我们也不需要它,因此我们将传递null。 第三个也是我们将实际使用的一个相对URL。

const historyPush = (path) => {  history.pushState({}, null, path)}
const historyReplace = (path) => {  history.replaceState({}, null, path)}

Now inside of our Link component, we’ll invoke historyPush or historyReplace depending on the replace prop,

现在,在我们的Link组件中,我们将根据replace historyReplace调用historyPushhistoryReplace

class Link extends Component {  static propTypes = {    to: PropTypes.string.isRequired,    replace: PropTypes.bool,  }  handleClick = (event) => {    const { replace, to } = this.props    event.preventDefault()
replace ? historyReplace(to) : historyPush(to)  }
render() {    const { to, children} = this.props
return (              {children}          )  }}

Now there’s just one more, albeit crucial addition we need to make. If you were to play around with our example app with our current router code, you’d notice a pretty big problem. When you navigate around, the URL would update, but the UI would stay exactly the same. This is because even though we’re changing the location with our historyReplace or historyPush functions, our te>s are unaware of that change and don’t know that they should re-render and re-match. To solve this problem, we need to keep track of which <Route>s have been rendered and call forceUpdate on them whenever a route changes.

现在只有一个,尽管我们需要添加一些重要的内容。 如果您使用我们当前的路由器代码来玩我们的示例应用程序,您会发现一个很大的问题。 当您四处浏览时,URL会更新,但UI会保持不变。 这是因为即使我们使用historyReplacehistoryPush函数更改位置,我们的 te>也不知道该更改,并且不知道它们应该重新呈现和重新匹配。 为了解决此问题,我们需要跟踪已渲染了which & lt; Route>,并在路线更改时对其进行ed and call forceUpdate。

React Router gets around this problem by having using a combination of setState, context, and history.listen inside of a Router component you wrap your code with.

React路由器使用的setState,上下文和的history.listen内的组合有获取解决此问题路由器组件您包装你的代码。

To keep our router simple, we’ll keep track of which te>s have been rendered by pushing their instances to an array, then whenever a location change occurs, we can loop through that array and call forceUpdate on all the instances.

为了简化路由器,我们将通过将其实例推送到数组来跟踪呈现了哪些 te>,然后只要发生位置更改,我们就可以遍历该数组并在所有实例上调用forceUpdate。

let instances = []
const register = (comp) => instances.push(comp)const unregister = (comp) => instances.splice(instances.indexOf(comp), 1)

Notice we’ve created two functions. We’ll call register whenever a te> is mounted and call unregister whenever it unmounts. Then, whenever we call historyPush or historyReplace (which we will every time a user clicks on a ), we can loop through those instances and forceUpdate.

注意,我们创建了两个函数。 每当安装 te>时,我们都会调用register在卸载时,我们会调用call unre gister。 然后,每当我们call histo ryPu sh or historyR E放置(我们将每次用户点击on a <链接>),我们可以通过在那些环stances and forceUpdate。

Let’s update our te> component first,

让我们先更新 te>组件,

class Route extends Component {  static propTypes: {    path: PropTypes.string,    exact: PropTypes.bool,    component: PropTypes.func,    render: PropTypes.func,  }
componentWillMount() {    addEventListener("popstate", this.handlePop)    register(this)  }
componentWillUnmount() {    unregister(this)    removeEventListener("popstate", this.handlePop)  }
...}

Now, let’s update historyPush and historyReplace

现在,让我们更新historyPushhistoryReplace

const historyPush = (path) => {  history.pushState({}, null, path)  instances.forEach(instance => instance.forceUpdate())}
const historyReplace = (path) => {  history.replaceState({}, null, path)  instances.forEach(instance => instance.forceUpdate())}

? now whenever a &lt;Link> is clicked and the location changes, each &lt;Route> will be aware of that and re-match and re-render.

? 现在,每当单击& lt;Lin k>且位置发生更改时, each &l t; Route>都会意识到这一点,并重新匹配并重新渲染。

Now, our full router code looks like this code below, and our example app above works perfectly with it.

现在,我们完整的路由器代码看起来像下面的代码,上面的示例应用程序可以完美地与之配合使用。

import React, { PropTypes, Component } from 'react'
let instances = []
const register = (comp) => instances.push(comp)
const unregister = (comp) =>      instances.splice(instances.indexOf(comp), 1)
const historyPush = (path) => {  history.pushState({}, null, path)  instances.forEach(instance => instance.forceUpdate())}
const historyReplace = (path) => {  history.replaceState({}, null, path)  instances.forEach(instance => instance.forceUpdate())}
const matchPath = (pathname, options) => {  const { exact = false, path } = options
if (!path) {    return {      path: null,      url: pathname,      isExact: true    }  }
const match = new RegExp(`^${path}`).exec(pathname)
if (!match)    return null
const url = match[0]  const isExact = pathname === url
if (exact && !isExact)    return null
return {    path,    url,    isExact,  }}
class Route extends Component {  static propTypes: {    path: PropTypes.string,    exact: PropTypes.bool,    component: PropTypes.func,    render: PropTypes.func,  }
componentWillMount() {    addEventListener("popstate", this.handlePop)    register(this)  }
componentWillUnmount() {    unregister(this)    removeEventListener("popstate", this.handlePop)  }
handlePop = () => {    this.forceUpdate()  }
render() {    const {      path,      exact,      component,      render,    } = this.props
const match = matchPath(location.pathname, { path, exact })
if (!match)      return null
if (component)      return React.createElement(component, { match })
if (render)      return render({ match })
return null  }}
class Link extends Component {  static propTypes = {    to: PropTypes.string.isRequired,    replace: PropTypes.bool,  }  handleClick = (event) => {    const { replace, to } = this.props
event.preventDefault()    replace ? historyReplace(to) : historyPush(to)  }
render() {    const { to, children} = this.props
return (              {children}          )  }}

Bonus: The React Router API also comes with a ct> component. Using the code we’ve previously written, creating this component is pretty straight forward

奖励:React Router API还带有 ct>组件。 使用我们先前编写的代码,创建此组件非常简单

class Redirect extends Component {  static defaultProps = {    push: false  }
static propTypes = {    to: PropTypes.string.isRequired,    push: PropTypes.bool.isRequired,  }
componentDidMount() {    const { to, push } = this.props
push ? historyPush(to) : historyReplace(to)  }
render() {    return null  }}

Notice this component isn’t actually rendering any UI, instead, it’s acting purely as a route director, hence the name.

请注意,此组件实际上并没有呈现任何UI,相反,它仅充当路由主管,因此具有名称。

I hope this has helped you create a better mental model of what’s happening in React Router while also helping you to gain an appreciation for React Router’s elegance and “Just Components” API. I’ve always said that React will make you a better JavaScript developer. I now also believe that React Router will make you a better React developer. Because everything is just components, if you know React, you know React Router.

我希望这可以帮助您创建一个更好的关于React Router发生情况的思维模型,同时也可以帮助您对React Router的优雅和“ Just Components” API有所了解。 我一直说React将使您成为一个更好JavaScript开发人员。 我现在也相信React Router将使您成为更好的React开发人员。 因为一切都只是组件,所以如果您了解React,就会知道React Router。

P.S. Shoutout to Ryan, who created the first implementation of the mini router and helped me with this post.

PS向Ryan致敬,他创建了迷你路由器的第一个实现,并帮助了我。

Follow me on Twitter and read more of my work on my blog.

在Twitter上关注我,并在我的博客上阅读我的更多工作。

翻译自: https://www.freecodecamp.org/news/build-your-own-react-router-v4-a9815f7d5e42/

你可能感兴趣的:(定位,java,vue,javascript,react,ViewUI)