使用React路由器(Usage with React Router)

Usage with React Router

所以你想用你的 Redux 应用程序进行路由。你可以用 React Router 使用它。Redux 将成为您的数据的真实来源,而 React Router 将成为您的 URL 的真实来源。在大多数情况下,除非您需要时间旅行和倒带触发更改 URL 的操作,否则将它们分开是很好的做法

安装React路由器

react-router在 npm 上可用。本指南假定您正在使用react-router@^2.7.0

npm install --save react-router

配置Fallback URL

在集成 React Router 之前,我们需要配置我们的开发服务器。事实上,我们的开发服务器可能不知道 React Router 配置中声明的路由。例如,如果您访问/todos并刷新,则需要指示您的开发服务器进行服务,index.html因为它是单页面应用程序。以下是如何使用流行的开发服务器启用此函数。

关于创建React应用程序的注意事项

配置Express

如果您正在 Express 使用index.html

app.get('/*', (req, res) => { res.sendFile(path.join(__dirname, 'index.html')) })

配置WebpackDevServer

如果您从 WebpackDevServer 中服务您的index.html:您可以添加到您的 webpack.config.dev.js 中:

devServer: { historyApiFallback: true }

将 React 路由器与 Redux 应用连接

在本章中,我们将使用 Todos 例子。我们建议您在阅读本章时复制它。

首先,我们将需要从阵营路由器输入<Router />和<Route />。以下是如何做到这一点:

import { Router, Route } from 'react-router'

在一个 React 应用程序中,通常当 URL 改变时,你会在<Router />中会包装<Route />,这样<Router />将匹配它的一个路径分支,并且呈现它们配置的组件。<Route />用于声明性地将路由映射到应用程序的组件层次结构。您将在pathURL 中使用的路径中声明路由,并在component路由匹配 URL 时声明单个组件。

const Root = () => ( <Router> <Route path="/" component={App} /> </Router> )

但是,在我们的 Redux 应用程序中,我们仍然需要<Provider />。<Provider />是 React Redux 提供的高级组件,它允许您将 Redux 绑定到 React(请参阅 React 的用法)。

然后我们将从 React Redux 中导入<Provider />:

import { Provider } from 'react-redux'

我们将在<Provider />包装<Router />,以便路由处理程序可以访问store。

const Root = { store }) => ( <Provider store={store}> <Router> <Route path="/" component={App} /> </Router> </Provider> )

现在,如果 URL 匹配“/” ,<App />组件将被呈现。另外,我们将添加可选(:filter)参数/,因为当我们尝试从URL中读取参数(:filter)时,我们会进一步需要它。

<Route path="/(:filter)" component={App} />

您可能想要从 URL 中删除散列(例如:http://localhost:3000/#/?_k=4sbb0i)。为此,您还需要从 React 路由器中导入browserHistory

import { Router, Route, browserHistory } from 'react-router'

并将其传递给<Router />以从 URL 中删除 hash 值:

<Router history={browserHistory}> <Route path="/(:filter)" component={App} /> </Router>

除非你的目标是像 IE9 这样的老式浏览器,否则你可以随时使用browserHistory

components/Root.js

import React from 'react' import PropTypes from 'prop-types' import { Provider } from 'react-redux' import { Router, Route, browserHistory } from 'react-router' import App from './App' const Root = { store }) => ( <Provider store={store}> <Router history={browserHistory}> <Route path="/(:filter)" component={App} /> </Router> </Provider> ) Root.propTypes = { store: PropTypes.object.isRequired } export default Root

我们还需要重构index.js将<Root />组件呈现给 DOM。

index.js

import React from 'react' import { render } from 'react-dom' import { createStore } from 'redux' import todoApp from './reducers' import Root from './components/Root' let store = createStore(todoApp) render( <Root store={store} />, document.getElementById('root') )

使用 React 路由器进行导航

React 路由器附带一个<Link />组件,可让您浏览应用程序。在我们的例子中,我们可以包装<Link />一个新的容器组件<FilterLink />,以便动态更改 URL。activeStyle={}属性让我们对活动状态应用样式。

containers/FilterLink.js

import React from 'react' import { Link } from 'react-router' const FilterLink = { filter, children }) => ( <Link to={filter === 'SHOW_ALL' ? '/' : filter} activeStyle={{ textDecoration: 'none', color: 'black' }} > {children} </Link> ) export default FilterLink

components/Footer.js

import React from 'react' import FilterLink from '../containers/FilterLink' const Footer = () => ( <p> Show: {' '} <FilterLink filter="SHOW_ALL"> All </FilterLink> {', '} <FilterLink filter="SHOW_ACTIVE"> Active </FilterLink> {', '} <FilterLink filter="SHOW_COMPLETED"> Completed </FilterLink> </p> ) export default Footer

现在,如果你点击<FilterLink />,你会看到你的网址会之间切换'/SHOW_COMPLETED','/SHOW_ACTIVE'和'/'。即使您使用浏览器返回,它也会使用浏览器的历史记录,并有效地转到以前的网址。

从URL读取

目前,即使 URL 更改,待办事项列表也不会被过滤。这是因为我们正在从<VisibleTodoList />的mapStateToProps()中过滤仍然是和state绑定的,而不是 URL。mapStateToProps有一个可选的第二个参数ownProps,该参数是传递<VisibleTodoList />给每个道具的对象

containers/VisibleTodoList.js

const mapStateToProps = (state, ownProps) => { return { todos: getVisibleTodos(state.todos, ownProps.filter) // previously was getVisibleTodos(state.todos, state.visibilityFilter) } }

现在我们没有传递任何东西给<App />所以ownProps是空的对象。要根据 URL 过滤我们的待办事项,我们想要传递 URL 参数给<VisibleTodoList />。

之前我们写过:<Route path="/(:filter)" component={App} />,它在App让一个params属性变得可用。

params属性是一个对象,每个参数都在 url 中指定。例如: 如果我们正在导航到localhost:3000/SHOW_COMPLETED__ ,则params等于{ filter: 'SHOW_COMPLETED' }。我们现在可以从<App />__ 读取URL 。

请注意,我们使用 ES6 解构的性质传递params到<VisibleTodoList />。

components/App.js

const App = { params }) => { return ( <div> <AddTodo /> <VisibleTodoList filter={params.filter || 'SHOW_ALL'} /> <Footer /> </div> ) }

下一步

现在您已经知道如何进行基本路由,您可以了解更多关于 React Router API 的信息

关于其他路由库的注意事项