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

 更新时间:2022年09月29日 09:43:38   作者:月光晒了很凉快  
Reducer是个纯函数,即只要传入相同的参数,每次都应返回相同的结果。不要把和处理数据无关的代码放在Reducer里,让Reducer保持纯净,只是单纯地执行计算,这篇文章主要介绍了Redux拆分reducer函数流程

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模块化拆分内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • react实现一个优雅的图片占位模块组件详解

    react实现一个优雅的图片占位模块组件详解

    这篇文章主要给大家介绍了关于react如何实现一个还算优雅的占位模块图片组件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-10-10
  • react项目中使用react-dnd实现列表的拖拽排序功能

    react项目中使用react-dnd实现列表的拖拽排序功能

    这篇文章主要介绍了react项目中使用react-dnd实现列表的拖拽排序,本文结合实例代码讲解react-dnd是如何实现,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • react路由跳转传参刷新页面后参数丢失的解决

    react路由跳转传参刷新页面后参数丢失的解决

    这篇文章主要介绍了react路由跳转传参刷新页面后参数丢失的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • 详解如何封装和使用一个React鉴权组件

    详解如何封装和使用一个React鉴权组件

    JavaScript 和 React 提供了灵活的事件处理机制,特别是通过利用事件的捕获阶段来阻止事件传播可以实现精细的权限控制,本文将详细介绍这一技术的应用,并通过实践案例展示如何封装和使用一个 React 鉴权组件,需要的可以参考下
    2024-03-03
  • 浅谈React 的引入

    浅谈React 的引入

    React相比于Vue,更注重对JS的掌握,Vue把能做的都做了,只剩下最简单的让开发者使用,开发者需要记忆Vue的特定指令后就可很轻松地开发。相反,React是提供了一种思路和方式,没有过多的限制,但要求会相对高些,需要开发者对JS达到精通的地步才能真正运用好React。
    2021-05-05
  • 在react中使用vue的状态管理的方法示例

    在react中使用vue的状态管理的方法示例

    这篇文章主要介绍了在react中使用vue的状态管理的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • React在组件中如何监听redux中state状态的改变

    React在组件中如何监听redux中state状态的改变

    这篇文章主要介绍了React在组件中如何监听redux中state状态的改变,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • React实现模糊搜索和关键字高亮的示例代码

    React实现模糊搜索和关键字高亮的示例代码

    这篇文章主要为大家详细介绍了React如何实现模糊搜索和关键字高亮的效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-11-11
  • React安装node-sass失败解决方案分享

    React安装node-sass失败解决方案分享

    Node-sass是一个库,它将Node.js绑定到LibSass(流行样式表预处理器Sass的C版本),它允许用户以令人难以置信的速度将.scss文件本地编译为css,并通过连接中间件自动编译,下面这篇文章主要给大家介绍了关于React安装node-sass失败解决的相关资料,需要的朋友可以参考下
    2022-11-11
  • 浅谈react路由传参的几种方式

    浅谈react路由传参的几种方式

    这篇文章主要介绍了浅谈react路由传参的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论