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模块化拆分内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
声明:本站所有文章 ,如无特殊说明或标注,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时 ,禁止复制 、盗用 、采集 、发布本站内容到任何网站 、书籍等各类媒体平台 。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 。