资讯专栏INFORMATION COLUMN

【全栈React】第19天: 用Redux进行数据管理

glumes / 1013人阅读

摘要:归约器函数负责返回应用当前全局状态的表示形式。当我们在存储上发送操作时将使用应用的当前状态和导致状态更新的操作来调用此归约器函数。回到我们的归约器我们可以检查的动作类型并采取适当的步骤创建下一个状态。我们将处理动作创造者中归约器的副作用。

本文转载自:众成翻译
译者:iOSDevLog
链接:http://www.zcfy.cc/article/3811
原文:https://www.fullstackreact.com/30-days-of-react/day-19/

随着我们了解了flux和Redux的知识,让我们将Redux整合到我们的应用中,并通过连接的应用。

昨天, 我们讨论了流量模式的原因, 它是什么, 我们有不同的选择, 以及介绍了Redux。

今天, 我们将回到代码和添加Redux在我们的应用。现在我们正在用它构建的应用是简单的, 这只会显示我们最后一次获取当前时间的页面。为了简单起见, 我们不会调用远程服务器, 只需使用 JavaScript 的Date 对象。

第一件事, 我们使用redux将不得不安装redux库。我们可以使用npm 包管理器来安装redux。在我们以前构建的应用的根目录中, 让我们运行npm install 命令来安装redux:

npm install --save redux

想使用redux, 我们还需要安装另一个包, react-redux , 帮助我们把reactredux绑在一起。

npm install --save react-redux

配置和设置

接下来的工作, 我们需要做的是在我们的应用内建立redux。我们需要执行以下操作才能设置它:

定义归约

创建Store

创建动作创造者

Store与我们的React意见联系起来

得益

第5步没有promises, 但它会更好, 嗯?

Precursor先驱

我们少量地讨论术语,(让我们的手指移动是更重要的)。我们将只是稍微调整我们的应用(烦人, 我知道, 但这是最后一次), 所以我们为了提供数据通过我们的应用可以创建一个包装组件。

完成后, 我们的应用树将具有以下形状:

[Root] -> [App] -> [Router/Routes] -> [Component]

废话少说, 让我们将我们的 src/App.js 移动到src/containers目录中, 我们需要同时更新来自我们的导入的一些路径。我们将使用几天前讨论的React路由材料。

我们将在 语句中包含几条路由, 以确保一次只显示一个。

import React from "react";

import {
  BrowserRouter as Router,
  Route,
  Switch
} from "react-router-dom"

// We"ll load our views from the `src/views`
// directory
import Home from "./views/Home/Home";
import About from "./views/About/About";

const App = props => {
  return (
    
      
        
        
      
    
  )
}

export default App;

此外, 我们将需要创建一个新的容器, 我们将调用Root , 这将包装我们的整个 组件, 并使可用的其余应用。让我们创建src/containers/Root.js 文件:

`touch src/containers/Root.js`

目前, 我们将在这里使用一个占位符组件, 但我们将在讨论存储时替换此内容。现在, 让我们导出 _一些东西_:

import React from "react";
import App from "./App";

const Root = (props) => {
  return (
    
  );
}

export default Root;

最后, 让我们更新的路由, 我们渲染我们的应用在src/index.js文件使用我们的新的Root 容器, 而不是它以前使用的App

import React from "react";
import ReactDOM from "react-dom";
import Root from "./containers/Root";
import "./index.css";

ReactDOM.render(
  ,
  document.getElementById("root")
);
添加Redux

现在有了一个坚实的应用结构就位, 我们可以开始添加Redux。我们将采取的步骤以配合一些我们将建立的大多数应用的Redux结构通常都是相同的。我们需要:

写一个根归约器

写 actionCreators

配置存储、rootReducer和应用

将视图连接到 actionCreators

我们故意保持这个高层次的介绍短一些, 所以坚持一下, 这一切都将在短期内变得更有意义。

让我们设置允许我们添加Redux的结构。我们将在src/redux 目录中完成几乎所有的工作。让我们创建该目录。

mkdir -p src/redux
touch src/redux/configureStore.js
touch src/redux/reducers.js

首先我们先创建归约器。虽然它听起来很复杂, 但是归约器实际上是相当直接的, 有一定的经验。归约器仅是 字面 函数。它的唯一责任是返回一个 next 状态的表示。

在Redux模式, 不像flux, 我们只在 整个 应用处理 一个 全局存储的。这使得事情变得更容易处理, 因为有一个地方的数据, 我们的应用生活。

root 归约器函数负责返回应用当前全局状态的表示形式。当我们在存储上发送操作时, 将使用应用的当前状态和导致状态更新的操作来调用此归约器函数。

让我们在一个文件中建立我们的根归约器在src/redux/reducers.js.。

// Initial (starting) state
const initialState = {
  currentTime: new Date().toString()
}

// Our root reducer starts with the initial state
// and must return a representation of the next state
const rootReducer = (state = initialState, action) => {
  return state;
}

export default rootReducer

I在函数中, 我们将第一个参数定义为初始状态 (第一次运行时, 不带参数调用rootReducer , 因此它总是在第一次运行时返回 initialState )。

这就是现在的 rootReducer。就像现在这样, state的价值总是和 initialState 一样。在我们的例子中, 这意味着我们的数据树有一个单一的currentTime键。

什么是动作?

这里的第二个参数是从存储区发送的操作。我们很快就会回来。现在,让我们来看看动作。

最起码, 一个动作 必须 包括一个type 键。type 键可以是我们想要的任何值, 但它必须存在。例如, 在我们的应用中, 我们将偶尔发送一项操作, 我们想告诉存储获取 最新 当前时间。我们可以将此操作称为FETCH_NEW_TIME 的字符串值。

我们可能从我们的存储发送的处理此更新的操作如下:

{
  type: "FETCH_NEW_TIME"
}

正如我们将通过键入这个字符串很多, 我们希望避免可能的拼写错误的地方, 它是常见的创建一个types.js 文件, 将操作类型导出为常量。让我们遵循这个约定, 创建一个src/redux/types.js 文件:

`export const FETCH_NEW_TIME = "FETCH_NEW_TIME";`

我们将从types.js 文件中引用它, 而不是使用"FETCH_NEW_TIME" 的硬编码字符串调用该操作:

import * as types from "./types";

{
  type: types.FETCH_NEW_TIME,
}

当我们想发送数据与我们的动作, 我们可以添加任何键, 我们想我们的动作。我们通常会看到这个所谓的payload 有效载荷, 但它可以被称为任何东西。这是一个公约, 调用附加信息的payload

我们的FETCH_NEW_TIME 动作将发送一个有效载荷与新的当前时间。因为我们想发送一个 序列化 值与我们的动作, 我们将发送新的当前时间的字符串值。

{
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString() // Any serializable value
}

回到我们的归约器, 我们可以检查的动作类型, 并采取适当的步骤, 创建下一个状态。在我们的情况下, 我们只储存payload。如果操作的typeFETCH_NEW_TIME, 我们将返回新的 currentTime (从我们的操作有效负载) 和其他状态 (使用 ES6 扩展语法):

export const rootReducer = (state = initialState, action) => {
  switch(action.type) {
    case types.FETCH_NEW_TIME:
      return { ...state, currentTime: action.payload}
    default:
      return state;
  }
}

请记住, 归约 必须 返回一个状态, 所以在默认情况下, _最起码_确保返回当前状态。

保持轻型化

由于归约器的功能每次调度一个动作, 我们要确保这些功能是尽可能简单和快速。我们不希望他们造成任何副作用或有太多的延迟。

我们将处理动作创造者中归约器的副作用。

在我们看动作创造者 (以及为什么我们称他们为动作创造者) 之前, 让我们把我们的存储与我们的应用挂钩。

我们将使用 react-redux 包将我们的视图连接到我们的redux存储。让我们确保使用npm安装此包:

npm install --save react-redux
将存储与视图挂钩

react-redux 包输出一个名为 Provider 的组件。Provider 组件使存储可以使用我们的应用中的所有容器组件, 而无需我们每次都需要手动传递它。

Provider 组件期望一个store 的属性, 它期望是一个有效的redux存储, 所以我们的应用没有错误运行之前,我们需要完成一个configureStore 功能,。现在, 让我们在应用中连接Provider 组件。我们将通过更新我们以前创建的包装Root 组件来使用Provider 组件来完成此项。

import { Provider } from "react-redux";
  // ...
const Root = (props) => {
  // ...

  return (
    
      
    
  );
}

请注意, 我们正在将store 值发送到Provider 组件, 但我们还没有创建该存储。现在我们来解决这个问题。

配置存储

为了创建一个存储, 我们将使用新的src/redux/configureStore.js 来导出将负责创建存储的函数。

我们如何创建一个存储?

redux包输出一个叫做 createStore 的函数, 它将为我们创建实际的存储区, 因此, 让我们打开 src/redux/configureStore.js 文件并导出一个称为configureStore()的函数 (我们将很快定义), 并导入createStore` 帮助器:

import {createStore} from "redux";
  // ...
export const configureStore = () => {
  // ...
}
  // ...
export default configureStore;

实际上我们在我们的存储还没有返回任何东西, 所以让我们实际创建的redux 存储使用 createStore 的功能, 我们从redux导入:

import {createStore} from "redux";

export const configureStore = () => {
  const store = createStore();

  return store;
}

export default configureStore;

如果我们在浏览器中加载我们的页面, 我们将看到我们有一个巨大的错误: 没有页面得到渲染。

redux给我们的错误告诉我们, 我们存储里没有归约器。如果没有归约器, 它将不知道如何处理动作或如何创建状态等。为了越过这个错误, 我们需要参考我们创建的 rootReducer。

createStore 函数要求我们将 rootReducer 作为第一个参数来传递。它还希望将初始状态作为第二个参数传递。我们将从我们创建的reducers.js 文件中导入这两个值。

import { rootReducer, initialState } from "./reducers"
  // ...
export const configureStore = () => {
  const store = createStore(
    rootReducer, // root reducer
    initialState, // our initialState
  );

  return store;
}

现在, 让我们通过调用 configureStore() 函数创建store 的实例来更新我们的Root.js 文件。

const Root = (props) => {
  const store = configureStore();

  return (
    
      
    
  );
}
连接视图 (续)

我们的应用中的一切都设置为使用redux, 而无需 多开销。redux 提供的一个更方便的方法是使用react-redux包导出的connect() 函数, 将状态树的片断 绑定 到不同的组件。

connect() 函数返回一个函数, 它期望第一参数是一个组件。这通常叫做高阶组件。

connect() 函数要求我们在函数中至少传递一个参数 (但通常我们会传递两个)。它所期望的第一个参数是一个函数, 它将被称为state 并期望一个返回的对象将数据连接到视图。让我们看看我们是否能在代码中揭开这种行为的神秘面纱。

我们将这个函数称为mapStateToProps 函数。因为它的责任是将状态映射到与组件的原始props合并的对象。

让我们在src/views/Home.js 中创建 home 视图, 并使用此connect() 函数来绑定currentTime 在我们的状态树中的值。

import { connect } from "react-redux";
  // ...
const mapStateToProps = state => {
  return {
    currentTime: state.currentTime
  }
}
export default connect(
  mapStateToProps
)(Home);

connect() 函数 自动 将函数的第一个参数中的任何键传递为Home 组件的props

在我们的演示案例中, Home 组件中的currentTime属性将映射到currentTime中的状态树键。让我们更新 Home 组件, 以显示currentTime中的值:

const Home = (props) => {
  return (
    

Welcome home!

Current time: {props.currentTime}

); }

虽然这个演示不是很有趣, 它表明我们有我们的Redux 应用建立了我们的 data 致力于全局状态和我们的视图组件映射数据。

明天, 我们将开始通过操作创建者来触发我们的全局状态的更新, 并通过将多个redux模块组合在一起来工作。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84723.html

相关文章

  • 全栈ReactReact 30教程索引

    摘要:今天我们将讨论创建组件的最终方案,即无状态函数的纯组件。今天我们正在研究一种处理提出的复杂数据的方法,称为体系结构。第天部署介绍今天,我们将探讨部署我们的应用所涉及的不同部分,以便外界可以使用我们的应用。 本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3758原文:https://www.fullstackreact.com/3...

    appetizerio 评论0 收藏0
  • 全栈React18: Flux 简介

    摘要:在方法中处理数据有三不同的角色派发器储存视图层我们的组件的主要思想是有一个单一源储存他们只能通过触发更新。这些操作负责调用派发器可以订阅更改并相应地更新自己的数据。与不同不使用派发器而是使用纯函数来定义数据变异函数。 本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3812原文:https://www.fullstackreact...

    mtunique 评论0 收藏0
  • 全栈React20: Redux动作

    摘要:去营救有一种方法我们把我们的归约器分成多个归约器每个都只负责状态树的叶子。此外我们还学习了如何扩展以使用多个归约器和动作以及多个连接的组件。 本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3825原文:https://www.fullstackreact.com/30-days-of-react/day-20/ 使用Redux,...

    SimonMa 评论0 收藏0
  • 全栈React21: Redux中间件

    摘要:本文转载自众成翻译译者链接原文今天,我们在方法中使用中间件来管理我们的代码中的复杂状态变化。中间件是一个很好的地方。我们中间件我们将实现一些中间件它将代表我们处理异步请求。中间件位于动作和归并器之间。让我们创建我们的第一个中间件。 本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3810原文:https://www.fullsta...

    Scott 评论0 收藏0
  • 全栈React23: 实现测试

    摘要:包包含由团队提供的测试实用程序。将在一个名为的目录中自动查找整个树中的测试文件是的带有下划线。让我们为时间轴组件创建第一个测试。其中之一是命令。现在我们已经编写了第一个测试并确认了我们的设置我们将在明天开始测试我们的时间轴组件。 本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3807原文:https://www.fullstac...

    airborne007 评论0 收藏0

发表评论

0条评论

glumes

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<