redux路由原理_Redux-First路由模型简介

查学文
2023-12-01

redux路由原理

by Michael Sargent

迈克尔·萨金特(Michael Sargent)

Redux-First路由模型简介 (An Introduction to the Redux-First Routing Model)

A routing library is a key component of any complex, single-page application. If you develop web apps with React and Redux, you’ve probably used, or at least heard of React Router. It’s a well-known routing library for React, and a great solution for many use cases.

路由库是任何复杂的单页应用程序的关键组件。 如果您使用React和Redux开发Web应用程序,那么您可能已经使用过,或者至少听说过React Router 。 它是React的著名路由库,也是许多用例的出色解决方案。

But React Router isn’t the only viable solution in the React/Redux ecosystem. In fact, there are tons of routing solutions built for React and for Redux, each with different APIs, features and goals — and the list is only growing. Needless to say, client-side routing isn’t going away anytime soon, and there’s still a lot of space for design in the routing libraries of tomorrow.

但是React Router并不是React / Redux生态系统中唯一可行的解​​决方案。 实际上,有为ReactRedux构建的大量路由解决方案,每种都有不同的API,功能和目标-并且列表还在不断增加。 不用说,客户端路由不会很快消失,而且明天的路由库中仍有很多设计空间。

Today, I want to bring your attention to the subject of routing in Redux. I’ll present and make a case for Redux-first routing — a paradigm that makes Redux the star of the routing model, and the common thread among many Redux routing solutions. I’ll demonstrate how to put together the core, framework-agnostic API in under 100 lines of code, before exploring options for real-world usage with React and other front-end frameworks.

今天,我想提请您注意Redux中的路由主题。 我将介绍Redux优先路由并为之做一个案例-该范例使Redux成为路由模型的明星 ,也是许多Redux路由解决方案中的共同点。 在探索与React和其他前端框架在现实世界中使用的选项之前,我将演示如何在不到100行的代码中整合与框架无关的核心API。

一点历史 (A Little History)

In the browser, the location (URL information) and session history (a stack of locations visited by the current browser tab) are stored in the global window object. They are accessible via:

在浏览器中, 位置 (URL信息)和会话历史记录 (当前浏览器选项卡访问的位置的堆栈)存储在全局window对象中。 可通过以下方式访问它们:

The History API offers the following history navigation methods, notable for their ability to update the browser’s history and location without necessitating a page reload:

History API提供以下历史记录导航方法 ,这些方法无需更新页面即可更新浏览器的历史记录和位置的能力而著称

  • pushState(href) — pushes a new location onto the history stack

    pushState(href) —将新位置推入历史记录堆栈

  • replaceState(href) — overwrites the current location on the stack

    replaceState(href) —覆盖堆栈上的当前位置

  • back() — navigates to the previous location on the stack

    back() —导航到堆栈上的上一个位置

  • forward() — navigates to the next location on the stack

    forward() —导航到堆栈上的下一个位置

  • go(index) — navigates to a location on the stack, in either direction.

    go(index) —沿任一方向导航到堆栈上的某个位置。

Together, the History and Location APIs enable the modern client-side routing paradigm known as pushState routing — the first protagonist of our story.

结合使用History和Location API,可以实现称为pushState路由的现代客户端路由范式-我们故事的第一位主角。

Now, it’s almost a crime to mention the History and Location APIs without mentioning a modern wrapper library like history.

现在,提及History和Location API而不提及诸如history这样的现代包装库几乎是一种犯罪。

ReactTraining/historyManage session history with JavaScriptgithub.com

ReactTraining / history 使用JavaScript github.com 管理会话历史

history provides a simple yet powerful API for interfacing with the browser history and location, while covering inconsistencies between different browser implementations. It’s used as a peer or internal dependency in many modern routing libraries, and I’ll make multiple references to it throughout this article.

history提供了一个简单而强大的API,用于与浏览器的历史记录和位置进行交互,同时涵盖了不同浏览器实现之间的不一致。 在许多现代路由库中,它被用作对等项或内部依赖项,在本文中,我将对其进行多次引用。

Redux和pushState路由 (Redux and pushState Routing)

The second protagonist of our story is Redux. It’s 2017, so I’ll spare you the introduction and get right to the point:

我们故事的第二个主角是Redux 。 现在是2017年,因此,我将为您介绍这些内容,并指出重点:

By using plain pushState routing in a Redux application, we split the application state across two domains: browser history and the Redux store.

通过在Redux应用程序中使用普通的pushState路由,我们将应用程序状态分为两个域:浏览器历史记录和Redux存储。

Here’s what that looks like with React Router, which instantiates and wraps history:

这是React Router的外观,它实例化并包装 history

history → React Router ↘                        view                 Redux ↗

Now, we know that not all data has to reside in the store. For example, local component state is often a suitable place to store data that’s specific to a single component.

现在,我们知道并非所有数据都必须驻留在store中 。 例如,本地组件状态通常是存储特定于单个组件的数据的合适位置。

But location data isn’t trivial. It’s a dynamic and important part of the application state — the kind of data that belongs in the store. Holding it in the store enables Redux luxuries like time-travel debugging, and easy access from any store-connected component.

但是位置数据并非易事。 它是应用程序状态中动态且重要的部分-属于商店的数据类型。 将其保存在商店中可以实现Redux的豪华性,例如时间旅行调试,还可以轻松地从任何商店连接的组件进行访问。

So how do we move the location into the store?

那么我们如何将位置移动到商店中?

There’s no getting around the fact that the browser reads and stores history and location information in the window, but what we can do is keep a copy of the location data in the store, and keep it in sync with the browser.

浏览器读取并在window存储历史记录和位置信息这一事实并没有得到解决,但是我们能做的就是在存储中保存位置数据的副本 ,并使其与浏览器保持同步。

Isn’t that what react-router-redux does for React Router?

那不是React react-router-redux对React Router的作用吗?

Yes, but only to enable the time-travel capabilities of the Redux DevTools. The application still depends on location data held in React Router:

是的,但是仅启用Redux DevTools的时间旅行功能。 该应用程序仍取决于React Router中保存的位置数据:

history → React Router ↘                   ↕    view                 Redux ↗

Using react-router-redux to read location data from the store instead of React Router is discouraged (due to potentially conflicting sources of truth).

使用react-router-redux从存储器中读出位置数据,而不是阵营路由器正在气馁 (由于真理的潜在冲突的源)。

Can we do better?

我们可以做得更好吗?

Can we build an alternative routing model — one that’s built from the ground up to play well with Redux, allowing us to read and update the location the Redux way — with store.getState() and store.dispatch()?

我们是否可以使用store.getState()store.dispatch()构建替代路由模型(从头开始构建以与Redux配合使用,从而允许我们以Redux方式读取和更新位置store.dispatch()

We absolutely can, and it’s called Redux-first routing.

我们绝对可以,这称为Redux-first路由

Redux-First路由 (Redux-First Routing)

Redux-first routing is a variation on pushState routing that makes Redux the star of the routing model.

Redux-first路由是pushState路由的变体 这使Redux成为路由模型的明星。

A Redux-first routing solution satisfies the following criteria:

Redux-first路由解决方案满足以下条件

  • The location is held in the Redux store.

    该位置在Redux商店中。
  • The location is changed by dispatching Redux actions.

    通过调度Redux操作来更改位置。
  • The application reads location data solely from the store.

    该应用程序仅从商店读取位置数据。
  • The store and browser history are kept in sync behind the scenes.

    商店和浏览器的历史记录在后台保持同步。

Here’s a basic idea of what that looks like:

这是看起来的基本概念:

history   ↕ Redux → router → view

Wait, aren’t there still two sources of location data?

等一下,还没有两个位置数据源吗?

Yes, but if we can trust that the browser history and Redux store are in sync, we can build our applications to only ever read location data from the store. Then, from the application’s point of view, there’s only one source of truth — the store.

是的,但是如果我们可以信任浏览器历史记录和Redux商店是同步的,那么我们可以构建应用程序以仅从该商店读取位置数据 。 然后,从应用程序的角度来看,只有一个事实来源—商店。

How do we accomplish Redux-first routing?

我们如何完成Redux-first路由?

We can start by creating a conceptual model, by merging the foundational elements of the client-side routing and Redux data lifecycle models.

我们可以通过创建概念模型,合并客户端路由和Redux数据生命周期模型的基础元素开始。

重访客户端路由模型 (Revisiting the Client-Side Routing Model)

Client-side routing is a multi-step process that starts with navigation and ends with renderingrouting itself is only one step in that process! Let’s review the details:

客户端路由是一个多步骤的过程,从导航开始到渲染结束— 路由本身只是该过程中的一个步骤! 让我们查看详细信息:

  • Navigation — Everything starts with a change in location. There are 2 types of navigation: internal and external. Internal navigation is accomplished from within the app (eg. via the History API), while external navigation occurs when the user interacts with the browser’s navigation bar or enters the application from an external site.

    导航 -一切都始于位置的改变。 有两种导航类型: 内部外部 。 内部导航是从应用程序内部完成的(例如,通过History API),而外部导航是在用户与浏览器的导航栏进行交互或从外部站点进入应用程序时发生的。

  • Responding to navigation — When the location changes, the application responds by passing the new location to the router. Older routing techniques relied on polling window.location to accomplish this, but nowadays we have the handy history.listen utility.

    响应导航 -位置更改时,应用程序通过将新位置传递到路由器来做出响应。 较旧的路由技术依靠轮询window.location来完成此操作,但是如今,我们有了方便的history.listen实用程序。

  • Routing — Next, the new location is matched to its corresponding page content. The code that handles this step is called a router, and it generally takes an input parameter of matching routes and pages called a route configuration.

    路由 -接下来,将新位置与其对应的页面内容进行匹配。 处理此步骤的代码称为路由器 ,它通常采用匹配路由和页面的输入参数,称为路由配置。

  • Rendering — Finally, the content is rendered on the client. This step may, of course, be handled by a front-end framework/library like React.

    渲染 -最后,内容在客户端上渲染。 当然,这一步骤可以由像React这样的前端框架/库来处理。

Note that routing libraries don’t have to handle every part of the routing model.

请注意,路由库不必处理路由模型的每个部分。

Some libraries, like React Router and Vue Router, do — while others, like Universal Router, are concerned solely with a single aspect (like routing), thus providing flexibility in the other aspects:

一些库(例如React Router和Vue Router ) 可以 -而其他库(例如Universal Router )仅关注单个方面(例如路由) ,因此在其他方面提供了灵活性:

重新审视Redux数据生命周期模型 (Revisiting the Redux Data Lifecycle Model)

Redux boasts a one-way data flow/lifecycle model that likely needs no introduction — but here’s a brief overview for good measure:

Redux拥有一种单向数据流/生命周期模型,可能不需要介绍—但是这里有一个简短的概述,可以很好地衡量这一点:

  • Action — Any change in state starts by dispatching a Redux action (a plain object containing a type and optional payload).

    动作 -状态的任何更改都将从调度Redux动作(包含type和可选有效负载的纯对象)开始。

  • Middleware — The action passes through the store’s chain of middlewares, where actions may be intercepted and additional behaviour may be executed. Middlewares are commonly used to handle side-effects in Redux applications.

    中间件 -动作经过商店的中间件链,在中间件链中可能会截获动作并执行其他行为。 中间件通常用于处理Redux应用程序中的副作用。

  • Reducer — The action then reaches the root reducer, which calculates the store’s next state as a pure function of the previous state and the received action. The root reducer may be composed of individual reducers that each handle a slice of the store’s state.

    Reducer —然后,操作到达根reducer,后者根据先前状态和接收到的动作的纯函数来计算商店的下一个状态。 根减少器可以由单独的减少器组成,每个减少器处理商店状态的一部分。

  • New state — The store saves the new state returned by the reducer, and notifies its subscribers of the change (in React, via connect).

    新状态 -商店保存由reducer返回的新状态,并将更改通知给订户 (在React中,通过connect )。

  • Rendering — Finally, the store-connected view may re-render in accordance with the new state.

    渲染 —最后,可以根据新状态重新渲染商店连接的视图。

构建Redux-First路由模型 (Building a Redux-First Routing Model)

The unidirectional nature of the client-side routing and Redux data lifecycle models lend themselves well to a merged model that satisfies the criteria we laid out for Redux-first routing.

客户端路由和Redux数据生命周期模型的单向性非常适合合并模型,该模型满足我们为Redux-first路由制定的标准。

In this model, the router is subscribed to the store, navigation is accomplished via Redux actions, and updates to the browser history are handled by a custom middleware. Let’s examine the details of this model:

在此模型中,路由器订阅了商店,导航通过Redux操作完成,浏览器历史记录的更新由自定义中间件处理。 让我们检查一下此模型的详细信息:

  • Internal navigation via Redux actions — Instead of using the History API directly, internal navigation is achieved by dispatching one of 5 navigation actions that mirror the history navigation methods.

    通过Redux操作进行内部导航 -通过调度5个反映历史导航方法的导航操作之一来实现内部导航,而不是直接使用History API。

  • Updating the browser history via middleware — A middleware is used to intercept the navigation actions and handle the side-effect of updating the browser history. Since the new location isn’t necessarily or easily known without first consulting the browser history (eg. in the case of a go action), the navigation actions are prevented from reaching the reducer.

    通过中间件更新浏览器历史记录 —中间件用于拦截导航操作并处理更新浏览器历史记录的副作用。 由于在未先查询浏览器历史记录的情况下(例如,在go动作的情况下)并不一定或不容易知道新位置,因此可以防止导航动作到达减速器。

  • Responding to navigation — The flow of execution continues with a history listener that responds to navigation (from both the middleware and external navigation) by dispatching a second action that does contain the new location.

    响应导航 -执行流程继续进行到history监听器响应定位(从中间件外部导航两者)通过调度, 包含新位置的第二动作

  • Location Reducer — The action dispatched by the listener then reaches the location reducer, which adds the location to the store. The location reducer also determines the shape of the location state.

    位置减少器 —侦听器分派的操作然后到达位置减少器,后者将位置添加到商店。 位置减少器还确定位置状态的形状

  • Connected routing — The store-connected router can then reactively determine the new page content when notified of a change in location in the store.

    连接的路由 -与商店连接的路由器可以在收到商店中位置更改的通知后以React方式确定新页面的内容。

  • Rendering — Finally, the page may be re-rendered with the new content.

    渲染 -最后,可以使用新内容重新渲染页面。

Note that this isn’t the only way to accomplish Redux-first routing — some variations feature the use of a store enhancer and/or additional logic in the middleware — but it’s a simple model that covers all of the bases.

请注意,这不是完成Redux-first路由的唯一方法-一些变体以在中间件中使用存储增强器和/或附加逻辑为特征-但这是涵盖所有基础的简单模型。

基本实现 (A Basic Implementation)

Following the model we just looked at, let’s implement the core API — the actions, middleware, listener, and reducer.

按照我们刚刚看过的模型,让我们实现核心API-操作,中间件,侦听器和reducer。

We’ll use the history package as an internal dependency, and build the solution incrementally. If you’d rather follow along with the final result, you may view it here.

我们将history包用作内部依赖项,并逐步构建解决方案。 如果您希望遵循最终结果,可以在此处查看

动作 (Actions)

We’ll start by defining the 5 navigation actions that mirror the history navigation methods:

我们将从定义与历史导航方法相似的5个导航动作开始:

// constants.jsexport const PUSH = 'ROUTER/PUSH';export const REPLACE = 'ROUTER/REPLACE';export const GO = 'ROUTER/GO';export const GO_BACK = 'ROUTER/GO_BACK';export const GO_FORWARD = 'ROUTER/GO_FORWARD';
// actions.jsexport const push = (href) => ({  type: PUSH,  payload: href,});
export const replace = (href) => ({  type: REPLACE,  payload: href,});
export const go = (index) => ({  type: GO,  payload: index,});
export const goBack = () => ({  type: GO_BACK,});
export const goForward = () => ({  type: GO_FORWARD,});

中间件 (Middleware)

Next, let’s define the middleware. It should intercept the navigation actions, call the corresponding history navigation methods, then stop the action from reaching the reducer — but leave all other actions undisturbed:

接下来,让我们定义中间件。 它应该拦截导航动作,调用相应的history导航方法,然后阻止该动作到达reducer,但保持所有其他动作不受干扰:

// middleware.jsexport const routerMiddleware = (history) => () => (next) => (action) => {  switch (action.type) {    case PUSH:      history.push(action.payload);      break;    case REPLACE:      history.replace(action.payload);      break;    case GO:      history.go(action.payload);      break;    case GO_BACK:      history.goBack();      break;    case GO_FORWARD:      history.goForward();      break;    default:      return next(action);  }};

If you haven’t had the chance to write or examine the internals of a Redux middleware before, check out this introduction.

如果您之前没有机会编写或检查Redux中间件的内部结构,请查看此介绍

历史听众 (History Listener)

Next, we’ll need a history listener that responds to navigation by dispatching a new action containing the new location information.

接下来,我们需要一个history侦听器,该侦听器通过调度包含新位置信息的动作来响应导航。

First, let’s add the new action type and creator. The interesting parts of the location are the pathname, search, and hash — so that’s what we’ll include in the payload:

首先,让我们添加新的动作类型和创建者。 位置中有趣的部分是pathnamesearchhash -因此,这就是我们将包含在有效负载中的内容:

// constants.jsexport const LOCATION_CHANGE = 'ROUTER/LOCATION_CHANGE';
// actions.jsexport const locationChange = ({ pathname, search, hash }) => ({  type: LOCATION_CHANGE,  payload: {    pathname,    search,    hash,  },});

Then let’s write the listener function:

然后让我们编写监听器函数:

// listener.jsexport function startListener(history, store) {  history.listen((location) => {    store.dispatch(locationChange({      pathname: location.pathname,      search: location.search,      hash: location.hash,    }));  });}

We’ll make one small addition — an initial locationChange dispatch, to account for the initial entry into the application (which doesn’t get picked up by the history listener):

我们将做一小部分添加-初始locationChange调度,以考虑到应用程序中的初始输入(历史监听程序不会选择该初始输入):

// listener.jsexport function startListener(history, store) {  store.dispatch(locationChange({    pathname: history.location.pathname,    search: history.location.search,    hash: history.location.hash,  }));
history.listen((location) => {    store.dispatch(locationChange({      pathname: location.pathname,      search: location.search,      hash: location.hash,    }));  });}

减速器 (Reducer)

Next, let’s define the location reducer. We’ll use a simple state shape, and do minimal work in the reducer:

接下来,让我们定义位置减少器。 我们将使用简单的状态形状,并在化简器中进行最少的工作:

// reducer.jsconst initialState = {  pathname: '/',  search: '',  hash: '',};
export const routerReducer = (state = initialState, action) => {  switch (action.type) {    case LOCATION_CHANGE:      return {        ...state,        ...action.payload,      };    default:      return state;  }};

申请代码 (Application Code)

Finally, let’s hook up our API into the application code:

最后,让我们将API连接到应用程序代码中:

// index.jsimport { combineReducers, applyMiddleware, createStore } from 'redux'import { createBrowserHistory } from 'history'import { routerReducer } from './reducer'import { routerMiddleware } from './middleware'import { startListener } from './listener'import { push } from './actions'
// Create the history objectconst history = createBrowserHistory()
// Build the root reducerconst rootReducer = combineReducers({  // ...otherReducers,  router: routerReducer,})  // Build the middlewareconst middleware = routerMiddleware(history)
// Create the storeconst store = createStore(rootReducer, {}, applyMiddleware(middleware))
// Start the history listenerstartListener(history, store)
// Now you can read location data from the store!let currentLocation = store.getState().router.pathname
// You can also subscribe to changes in the location!let unsubscribe = store.subscribe(() => {  let previousLocation = currentLocation  currentLocation = store.getState().router.pathname
if (previousLocation !== currentLocation) {    // You can render your application reactively here!  }})
// And you can dispatch navigation actions from anywhere!store.dispatch(push('/about'))

And that’s all there is to it! Using our tiny (under 100 lines of code) API, we’ve met all of the criteria for Redux-first routing:

这就是全部! 使用我们的微小(不到100行代码)API,我们满足了Redux-first路由的所有标准:

  • The location is held in the Redux store. ✔

    该位置在Redux商店中。 ✔
  • The location is changed by dispatching Redux actions. ✔

    通过调度Redux操作来更改位置。 ✔
  • The application reads location data solely from the store. ✔

    该应用程序仅从商店读取位置数据。 ✔
  • The store and browser history are kept in sync behind the scenes. ✔

    商店和浏览器的历史记录在后台保持同步。 ✔

View all the files together here — feel free to import them into your project, or use it as a starting point to develop your own implementation.

在此处一起查看所有文件 -随时将它们导入到您的项目中,或将其用作开发自己的实现的起点。

redux-first-routing包 (The redux-first-routing package)

I’ve also put the API together into the redux-first-routing package, which you may npm install and use in the same way.

我还将API整合到redux-first-routing包中,您可以以相同的方式npm install和使用它。

mksarge/redux-first-routingredux-first-routing — A minimal, framework-agnostic base for accomplishing Redux-first routing.github.com

mksarge / redux-first-routing redux-first-routing —一个最小的,与框架无关的基础,用于完成Redux-first路由。 github.com

It includes an implementation similar to the one we built here, but with the notable addition of query parsing via the query-string package.

它包含与我们在此处构建的实现类似的实现,但值得注意的是通过query-string包增加了查询解析。

Wait — what about the actual routing component?

等待-实际的路由组件如何?

You may have noticed that redux-first-routing is only concerned with the navigational aspect of the routing model:

您可能已经注意到redux-first-routing仅与路由模型的导航方面有关:

By decoupling the navigational aspect from the other aspects of our routing model, we’ve gained some flexibility — redux-first-routing is both router-agnostic, and framework-agnostic.

通过将导航方面与路由模型的其他方面分离,我们获得了一定的灵活性redux-first-routing既与路由器无关 ,又与框架无关

You can therefore pair it with a library like Universal Router to create a complete Redux-first routing solution for any front-end framework:

因此,您可以将其与通用路由器之类的库配对,以为任何前端框架创建完整的Redux-first路由解决方案:

Or, you could build opinionated bindings for your framework of choice — and that’s what we’ll do for React in the next and final section of this article.

或者,您可以为您选择的框架构建自以为是的绑定-这就是我们将在本文的下一个和最后一节中为React所做的。

与React结合使用 (Usage with React)

Let’s finish our exploration by looking at how we might build store-connected components for declarative navigation and routing in React.

让我们通过研究如何构建存储连接的组件来在React中进行声明式导航和路由来完成我们的探索。

声明式导航 (Declarative Navigation)

For navigation, we can use a store-connected <Link/> component similar to the one in React Router and other React routing solutions.

为了进行导航,我们可以将存储连接的<Lin k />组件模拟与React Route r和其他React路由解决方案中的组件类似。

It simply overrides the default behaviour of anchor element <a/> and dispatches a push action when clicked:

它简单地覆盖锚固元件的默认行为< A />和dispatc hes点击时推动作:

// Link.jsimport React from 'react';import { connect } from 'react-redux';import { push as pushAction, replace as replaceAction } from './actions';
const Link = (props) => {  const { to, replace, children, dispatch, ...other } = props;
const handleClick = (event) => {    // Ignore any click other than a left click    if ((event.button && event.button !== 0)      || event.metaKey      || event.altKey      || event.ctrlKey      || event.shiftKey      || event.defaultPrevented === true) {      return;    }      // Prevent the default behaviour (page reload, etc.)    event.preventDefault();
// Dispatch the appropriate navigation action    if (replace) {      dispatch(replaceAction(to));    } else {      dispatch(pushAction(to));    }  };
return (    <a href={to} onClick={handleClick} {...other}>      {children}    </a>);};
export default connect()(Link);

You may find a more complete implementation here.

您可以在此处找到更完整的实现。

声明式路由 (Declarative Routing)

While there’s not much to a navigational component, there are countless ways to design a routing component — making it the most interesting part of any routing solution.

尽管导航组件并没有太多内容,但是设计路由组件的方法却不胜枚举,这使其成为任何路由解决方案中最有趣的部分。

What is a router, anyway?

路由器什么?

You can generally view a router as a function or black box with two inputs and one output:

通常,您可以将路由器视为具有两个输入和一个输出的功能或黑匣子:

route configuration ↘                      matched content  current location  ↗

Though the routing and subsequent rendering may occur in separate steps, React makes it easy and intuitive to bundle them together into a declarative routing API. Let’s look at two strategies for accomplishing this.

尽管路由和随后的呈现可能会在单独的步骤中进行,但是React使将它们捆绑到声明性路由API中变得容易而直观。 让我们看一下实现这一目标的两种策略。

Strategy 1: A monolithic <Router/> component

策略1:整体式<Route r />组件

We can use a monolithic, store-connected <Router/> component that:

我们可以使用与存储连接的整体式<Route r />组件,该组件可以:

  • accepts a route configuration object via props

    通过道具接受路线配置对象
  • reads the location data from the Redux store

    从Redux存储读取位置数据
  • calculates the new content whenever the location changes

    每当位置更改时计算新内容
  • renders/re-renders the content as appropriate.

    适当地渲染/重新渲染内容。

The route configuration may be a plain JavaScript object that contains all of the matching paths and pages (a centralized route configuration).

路由配置可以是包含所有匹配路径和页面的纯JavaScript对象( 集中式路由配置)。

Here’s how this might look:

这可能是这样的:

const routes = [  {    path: '/',    page: './pages/Home',  },  {    path: '/about',    page: './pages/About',  },  {    path: '*',    page: './pages/Error',  },]
React.render(  <Provider store={store}>    <Router routes={routes}>  </Provider>,  document.getElementById('app'))

Pretty simple, right? No need for nested JSX routes — just a single route configuration object, and a single router component.

很简单,对吧? 不需要嵌套的JSX路由-只需一个路由配置对象和一个路由器组件。

If this strategy is appealing to you, check out my more complete implementation in the redux-json-router library. It wraps redux-first-routing and provides React bindings for declarative navigation and routing using the strategies we’ve examined so far.

如果此策略吸引您,请在redux-json-router库中查看我更完整的实现。 它包装了redux-first-routing ,并使用到目前为止已经研究过的策略提供了用于声明式导航和路由的React绑定。

mksarge/redux-json-routerredux-json-router - Declarative, Redux-first routing for React/Redux browser applications.github.com

mksarge / redux-json-router redux-json- router- 用于React / Redux浏览器应用程序的声明式Redux-first路由。 github.com

Strategy 2: Composable <Route/> components

策略2:可组合的<Rout e />组件

While a monolithic component may be a simple way to achieve declarative routing in React, it’s definitely not the only way.

虽然单片组件可能是在React中实现声明式路由的一种简单方法,但绝对不是唯一的方法。

The composable nature of React allows another interesting possibility: using JSX to define routes in a decentralized manner. Of course, the prime example is React Router’s <Route/> API:

React的可组合性提供了另一个有趣的可能性:使用JSX以分散的方式定义路由。 当然,主要的例子是React Router的<Rout e /> API:

React.render(  <BrowserRouter>    <Route path='/' component={Home}/>    <Route path='/about component={About}/>    ...  </BrowserRouter>

Other routing libraries explore this idea too. While I haven’t had the chance do it, I don’t see any reason why a similar API couldn’t be implemented on top of the redux-first-routing package.

其他路由库也探索了这个想法。 虽然我没有机会这样做,但我看不出没有任何理由无法在redux-first-routing软件包之上实现类似的API。

Instead of relying on location data provided by <BrowserRouter/>, the &lt;Route/> component could simply connect to the store:

, the &l t; Route />组件可以不依赖<BrowserRoute r />提供的位置数据, the &l ould si连接到商店:

React.render(  <Provider store={store}>    <Route path='/' component={Home}/>    <Route path='/about component={About}/>    ...  </Provider>

If that’s something that you’re interested in building or using, let me know in the comments! To learn more about different route configuration strategies, check out this introduction on React Router’s website.

如果您对构建或使用该产品感兴趣,请在评论中让我知道! 要了解有关不同路由配置策略的更多信息,请在React Router的网站上查看介绍。

结论 (Conclusion)

I hope this exploration has helped deepen your knowledge about client-side routing and has shown you how simple it is to accomplish it the Redux way.

我希望这种探索能帮助您加深对客户端路由的了解,并向您展示实现Redux方法的简单性。

If you’re looking for a complete Redux routing solution, you can use the redux-first-routing package with a compatible router listed in the readme. And if you find yourself needing to develop a tailored solution, hopefully this post has given you a good starting point for doing so.

如果您正在寻找完整的Redux路由解决方案,则可以将redux-first-routing包与自述文件中列出的兼容路由器一起使用。 而且,如果您发现自己需要开发量身定制的解决方案,希望这篇文章为您提供了一个良好的起点。

If you’d like to learn more about client-side routing in React and Redux, check out the following articles — they were instrumental in helping me better understand the topics I covered here:

如果您想了解有关React和Redux中客户端路由的更多信息,请查看以下文章-它们有助于我更好地理解此处介绍的主题:

Client-side routing is a space with endless design possibilities, and I’m sure some of you have played with ideas similar to the ones I’ve shared here. If you’d like to continue the conversation, I’ll be glad to connect with you in the comments or via Twitter. Thanks for reading!

客户端路由是一个具有无限设计可能性的空间,我敢肯定,你们中的某些人所产生的想法与我在这里分享的想法类似。 如果您想继续对话,我们很乐意在评论中或通过Twitter与您联系。 谢谢阅读!

Edit 22/06/17: Also check out this article on redux-first-router, a separate project that uses intelligent action types to achieve powerful routing capabilities.

编辑22/06/17:另请参阅有关redux-first-router 文章redux-first-router 是一个单独的项目,该项目使用智能操作类型来实现强大的路由功能。

翻译自: https://www.freecodecamp.org/news/an-introduction-to-the-redux-first-routing-model-98926ebf53cb/

redux路由原理

 类似资料: