Redux模块化拆分reducer函数流程介绍

目录
  • 1. 概述
  • 2. 方式1-单纯文件拆分
  • 3. 方式2-使用中间件redux-thunk进行模块拆分

1. 概述

使用 redux 库中提供的 combineReducers 方法,可以将多个拆分 reducer 函数合并成统一的 reducer 函数,提供给 createStore 来使用。我们可以将 Redux 进行模块化拆分,再利用这个函数,将多个拆分 reducer 函数合并成统一的 reducer 函数,再传给 createStore 来使用。

2. 方式1-单纯文件拆分

redux 入口文件(store/index.js):

// 导入redux中的createStore创建仓库数据的方法
// combineReducers 用来合并多个拆分后的 reducer方式,返回一个新 reducer
// applyMiddleware 扩展redux功能
import { createStore, combineReducers, applyMiddleware } from 'redux'
// 配合浏览器安装的插件来进行redux调试所用
// 开发时有用,生产要关闭
import { composeWithDevTools } from '@redux-devtools/extension'
// 导入拆分开的模块
import count from './reducers/count'
import film from './reducers/film'
// 合并多个模块中的 reducer 函数,并且返回一个新的 reducer 函数
const reducer = combineReducers({
  // key:value
  // key:它是在获取 state 数据时的命名空间名称,redux 中没有 dispatch 操作的命名空间名称
  // 如果你进行了 redux 模块化拆分,则需要注意 type 的类型名称不能重名,如果重名则都会执行
  // type: 以拆分后的文件名称为前缀:xxx_type 类型名,不会重名
  // value:拆分后的 reducr 纯函数
  count,
  film
})
const store = createStore(
  reducer,
  composeWithDevTools()
)
// 导出
export default store

计数模块(count.js):

// 计数模块
// 初始state数据
const initState = {
  num: 100
}
// 定义一个纯函数reducer,专门用来操作state中的数据,要返回一个新的state
const reducer = (state = initState, action) => {
  if (action.type === 'count_add_num') return { ...state, num: state.num + action.payload }
  return state;
}
// 导出
export default reducer

电影列表模块(film.js):

// 电影列表展示模块
// 初始state数据
const initState = {
  nowplayings: []
}
// 定义一个纯函数reducer,专门用来操作state中的数据,要返回一个新的state
const reducer = (state = initState, action) => {
  if (action.type === 'film_set_nowplayings') return { ...state, nowplayings: action.payload }
  return state;
}
// 导出
export default reducer

计数器模块的装饰器函数(connect.js):

import { connect } from 'react-redux'
// todo... 一会要配置路径别名,它引入时就会短一些
// import countAction from '../../store/actionCreators/countAction'
import countAction from '@/store/actionCreators/countAction'
const mapDispatchToProps = dispatch => ({
  ...countAction(dispatch)
})
export default connect(state => state.count, mapDispatchToProps)

countAction.js:

export default dispatch => ({
  add(n = 1) {
    dispatch({ type: 'count_add_num', payload: n })
  }
})

App.jsx:

import React, { Component } from 'react'
import { Switch, Route, Link } from 'react-router-dom'
import Count from './views/Count'
import Nowplaying from './views/Nowplaying'
class App extends Component {
  render() {
    return (
      <div>
        <div>
          <Link to='/nowplaying'>nowplaying</Link> --
          <Link to='/count'>count</Link>
        </div>
        <hr />
        {/* 定义路由规则 */}
        <Switch>
          <Route path="/nowplaying" component={Nowplaying} />
          <Route path="/count" component={Count} />
        </Switch>
      </div>
    )
  }
}
export default App

计数器视图(index.jsx):

// 计数组件
import React, { Component } from 'react'
import connect from './connect'
@connect
class Count extends Component {
  render() {
    return (
      <div>
        <h3>{this.props.num}</h3>
        <button onClick={() => this.props.add()}>累加NUM</button>
      </div>
    )
  }
}
export default Count

上面是同步操作的模块拆分(针对计数器模块做的演示),下面是异步操作的模块化拆分,以电影播放列表为例。

电影模块的装饰器函数(connect.js):

import { connect } from 'react-redux'
import filmAction from '@/store/actionCreators/filmAction'
export default connect(state => state.film, dispatch => filmAction(dispatch))

filmAction.js:

import { getNowPlayingFilmListApi } from '@/api/filmApi'
export default dispatch => ({
  add(page = 1) {
    getNowPlayingFilmListApi(page).then(ret => {
      dispatch({ type: 'film_set_nowplayings', payload: ret.data.films })
    })
  }
})
// async 和 await 写法
// export default dispatch => ({
//   async add(page = 1) {
//     let ret = await getNowPlayingFilmListApi(page)
//     dispatch({ type: 'film_set_nowplayings', payload: ret.data.films })
//   }
// })

filmApi.js:

import { get } from '@/utils/http'
export const getNowPlayingFilmListApi = (page = 1) => {
  return get(`/api/v1/getNowPlayingFilmList?cityId=110100&pageNum=${page}&pageSize=10`)
}

电影模块视图(index.jsx):

// 电影展示列表组件
import React, { Component } from 'react'
import connect from './connect'
@connect
class Nowplaying extends Component {
  componentDidMount() {
    this.props.add()
  }
  render() {
    return (
      <div>
        {this.props.nowplayings.length === 0 ? (
          <div>加载中...</div>
        ) : (
          this.props.nowplayings.map(item => <div key={item.filmId}>{item.name}</div>)
        )}
      </div>
    )
  }
}
export default Nowplaying

3. 方式2-使用中间件redux-thunk进行模块拆分

关于 Redux 的中间件的原理,可以去阅读下面这篇文章,文章写得非常精彩!

传送门

概述:

redux-thunk 它是由 redux 官方开发出来的 redux 中间件,它的作用:解决 redux 中使用异步处理方案。redux-thunk 中间件可以允许在 connect 参数 2 中派发任务时返回的是一个函数,此函数形参中,redux-thunk 会自动注入一个 dispatch 派发函数,从而让你调用 dispath 函数来派发任务给 redux,从而实现异步处理。

安装:

yarn add redux-thunk

使用:

上文提到了对异步操作的处理,在上文基础上,我们修改成使用中间件进行处理的写法。

index.js:

// 导入redux中的createStore创建仓库数据的方法
// combineReducers 用来合并多个拆分后的 reducer方式,返回一个新 reducer
// applyMiddleware 扩展redux功能
import { createStore, combineReducers, applyMiddleware } from 'redux'
// 配合浏览器安装的插件来进行redux调试所用
// 开发时有用,生产要关闭
import { composeWithDevTools } from '@redux-devtools/extension'
// 导入拆分开的模块
import count from './reducers/count'
import film from './reducers/film'
import thunk from 'redux-thunk'
// 合并多个模块中的 reducer 函数,并且返回一个新的 reducer 函数
const reducer = combineReducers({
  count,
  film
})
const store = createStore(
  reducer,
  composeWithDevTools(applyMiddleware(thunk))
)
// 导出
export default store

connect.js:

import { connect } from 'react-redux'
// actions 这是一个对象 {a:funtion(){}}
import * as actions from '@/store/actionCreators/filmAction'
export default connect(state => state.film, actions)

filmAction.js:

import { getNowPlayingFilmListApi } from '@/api/filmApi'
const addActionCreator = data => ({ type: 'film_set_nowplayings', payload: data })
// 异步
export const add = (page = 1) => async dispatch => {
  let ret = await getNowPlayingFilmListApi(page)
  dispatch(addActionCreator(ret.data.films))
}

到此这篇关于Redux模块化拆分reducer函数流程介绍的文章就介绍到这了,更多相关Redux模块化拆分内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一文详解React Redux使用方法

    目录 一.理解JavaScript纯函数 1.1 纯函数的概念 1.2 副作用概念的理解 1.3 纯函数在函数式编程的重要性 二.Redux的核心思想 2.1 为什么需要 Redux 2.2 Redux的核心概念 2.2.1 store 2.2.2 action 2.2.3 reducer 2.3 Redux的三大原则 2.3.1 单一数据源 2.3.2 State是只读的 2.3.3 使用纯函数来执行修改 2.4 Redux 工作流程 三.Redux基本使用 3.1 创建Store的过程 3.

  • 一文理解Redux及其工作原理

    目录 一.是什么 二.工作原理 三.如何使用 小结 一.是什么 React是用于构建用户界面的,帮助我们解决渲染DOM的过程 而在整个应用中会存在很多个组件,每个组件的state是由自身进行管理,包括组件定义自身的state.组件之间的通信通过props传递.使用Context实现数据共享 如果让每个组件都存储自身相关的状态,理论上来讲不会影响应用的运行,但在开发及后续维护阶段,我们将花费大量精力去查询状态的变化过程 这种情况下,如果将所有的状态进行集中管理,当需要更新状态的时候,仅需要对这个管

  • Redux模块化拆分reducer函数流程介绍

    目录 1. 概述 2. 方式1-单纯文件拆分 3. 方式2-使用中间件redux-thunk进行模块拆分 1. 概述 使用 redux 库中提供的 combineReducers 方法,可以将多个拆分 reducer 函数合并成统一的 reducer 函数,提供给 createStore 来使用.我们可以将 Redux 进行模块化拆分,再利用这个函数,将多个拆分 reducer 函数合并成统一的 reducer 函数,再传给 createStore 来使用. 2. 方式1-单纯文件拆分 redu

  • jsp、struts、spring、mybatis实现前端页面功能模块化拆分的方案

    前端页面功能模块化拆分 当一个系统的功能很多时,不可能所有功能模块的页面都写在一个页面里面,这时就需要将不同功能模块的页面拆分出去,就像模板一样,需要哪块的功能就调用哪块的页面,然后加载相应数据并展示到相应的页面. 本应用的使用spring+struts+mybatis+jsp的方式,用两种方案来完成前端页面功能的拆分. 方案一: 在JSP页面中,利用EL表达式或者Java代码的方式,在后台完成页面数据的填充.然后在js中来完成页面的切换. jsp代码: 业务详情模块页面:riskDetailI

  • Linux系统创建TCP连接流程介绍

    目录 Linux创建TCP的步骤 服务端 客户端 TCP建立流程 示例代码 Linux创建TCP的步骤 TCP编程需要客户端和服务器两套编码,其创建TCP的流程也是不完全一致的 服务端 使用socket函数创建一个套接字 使用setsockopt函数设置套接字的属性 使用bind函数绑定IP地址.端口信息到套接字上使用listen函数监听指定端口 使用accept函数接收客户端的连接请求 使用send/recv和read/write函数进行数据的收发 使用close函数关闭网络连接和监听 客户端

  • Python的函数使用介绍

    目录 1 跳出循环-break 2 python函数 2.1 内置函数 2.2 自定义函数 2.3 main函数 1 跳出循环-break python提供了一种方便快捷的跳出循环的方法-break, 示例如下,计算未知数字个数的总和: if __name__ == "__main__": sum = 0 while True: num = str(input('输入的数字 (或者 "完成"): ')) if num == '完成': break #跳出循环 sum

  • Python实现将DNA序列存储为tfr文件并读取流程介绍

    最近导师让我跑模型,生物信息方向的,我一个学计算机的,好多东西都看不明白.现在的方向大致是,用深度学习的模型预测病毒感染人类的风险. 既然是病毒,就需要拿到它的DNA,也就是碱基序列,然后把这些ACGT序列丢进模型里面,然后就是预测能不能感染人类,说实话,估计结果不会好,现在啥都是transformer,而且我看的这篇论文,我认为仅仅从DNA序列大概预测不出什么东西. 但是就那样吧,现在数据去哪里下载,需要下载什么样的数据,下载完成后怎么处理我还是一脸懵逼,但是假设上面都处理好了,然后即使把数据

  • Flask表单与表单验证实现流程介绍

    目录 表单介绍 WTForms 和 Flask-WTF 创建表单 表单字段 验证器 表单介绍 说到表单,在HTML中表单的创建时通过<form>标签实现的,在<form>标签内部,字段通过使用<input>标签等定义.比如一个表单内部有用户名,密码框这些,都是通过<input>,<label>标签等实现的. 一个简单的表单: <form> First name:<br> <input type="text&

  • python flask sqlalchemy连接数据库流程介绍

    1.安装flask_sqlalchemy和pymysql包 pip install flask-sqlalchemy pip install pymysql 2.进行配置 使用Flask-SQLAlchemy扩展操作数据库,首先需要通过URL建立数据库连接,必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI中. HOSTNAME = '127.0.0.1'PORT     = '3306'DATABASE = 'flask_test'USERNAME = 'root'P

  • Vue支持搜索与筛选的用户列表实现流程介绍

    目录 1. 常规风格的示例工程开发 2. 使用组合式API重构用户列表页面 3. 优化用户列表页面 1. 常规风格的示例工程开发 首先新建一个名为 normal.html 的测试文件,在HTML文件的head标签中引入Vue框架并设置常规的模板字段如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv=

  • Vue数据增删改查与表单验证的实现流程介绍

    目录 1. 准备工作 2. 弹出窗口 3. 新增更新功能 4. 删除功能 5. 表单验证 6. 接口文档 1. 准备工作 后台服务接口,对书本的增删改查操作 2. 弹出窗口 进入ElementUi官网, 找到Dialog对话框,可以参考“嵌套表单的dialog”实现. 该步骤先实现弹出窗口的前端逻辑,并不会调用后台接口服务进行实际的业务操作. BookList.vue <!-- 弹出窗口:增加和修改书本信息共用一个弹出窗口,需要根据用户的选择动态的设置弹出窗口的标题 :tile 通过绑定值的方式

  • oracle中length、lengthb、substr、substrb函数用法介绍

    我记得我曾经在开发form的时候犯过这样一个错误,对于form中的某个字段,对应于数据库中某张表的字段,假设在数据库中这个字段一般也就用到20个汉字的长度,后来我在开发form的时候,设置item类型长度的时候,我惯性的设置成了50byte,想着就算是20个汉字,最多也就占40个byte长度嘛.可是,就因为这一个想当然,结果出现错误了,后来发现数据库字符集编码是utf8,那么应该设置为60.从那以后,每次涉及到给字段设置长度的时候,我都会特别注意下,到底是啥编码. 在oracle中,比较常见的可

随机推荐