目录
1.知识点
2.状态(数据)管理
3.Redux——核心概念
3.1state 对象
3.1.1state 是只读的
3.1.2通过纯函数修改 state
3.2Reducer 函数
3.3action 对象
3.4Store 对象
3.4.1Redux.createStore 方法
3.4.2getState() 方法
3.4.3dispatch() 方法
3.4.4action 创建函数
3.4.5subscribe() 方法
4.Redux——工作流
5.Redux——Reducers 分拆与融合
5.1combineReducers() 方法
6.react-redux
6.1安装
6.2 Provider 组件
6.3connect 方法
7.Redux DevTools extension
8.异步 action
8.1package.json 配置
8.2./src/setupProxy.js 配置
9.Middleware
9.1redux.applyMiddleware()
10.redux-chunk
10.1安装
10.2redux-chunk下使用redux-devtools-extension
各组件之间,父组件与子组件孙组件或者层次更下级的组件之间 以及无嵌套兄弟级间要维护和交互数据,光通过props进行传递非常的麻烦与复杂。
前端应用越来越复杂,要管理和维护的数据也越来越多,为了有效的管理和维护应用中的各种数据,我们必须有一种强大而有效的数据管理机制,也称为状态管理机制,Redux 就是解决该问题的。
Redux 是一个独立的 JavaScript 状态管理库,与非 React 内容之一。可以通过独立的中间件将Redux和React联系起来。
引入Redux的js文件,文件地址参考:https://www.bootcdn.cn/redux/。
理解 Redux 核心几个概念与它们之间的关系
通常我们会把应用中的数据存储到一个对象树(Object Tree) 中进行统一管理,我们把这个对象树称为:state
这里需要注意的是,为了保证数据状态的可维护和测试,不推荐直接修改 state 中的原数据
通过纯函数修改state。
什么是纯函数?
纯函数
使用纯函数的好处
function todo(state, action) {
switch(action.type) {
case 'ADD':
return [...state, action.payload];
break;
case 'REMOVE':
return state.filter(v=>v!==action.payload);
break;
default:
return state;
}
}
上面的 todo 函数就是 Reducer 函数
reducer函数的作用:用于接收原始(上一次)的state,并返回一个新的state数据。
我们对 state 的修改是通过 reducer 纯函数来进行的,同时通过传入的 action 来执行具体的操作,action 是一个对象
type 属性 : 表示要进行操作的动作类型,增删改查……
payload属性 : 操作 state 的同时传入的数据
但是这里需要注意的是,我们不直接去调用 Reducer 函数,而是通过 Store 对象提供的 dispatch 方法来调用,store.dispath()方法:用于提交和修改数据。
为了对 state,Reducer,action 进行统一管理和维护,我们需要创建一个 Store 对象。
let store = Redux.createStore((state, action) => {
// ...
}, []);
todo
用户操作数据的 reducer 函数
function todo(){
return [1,2,3];
}
[]
初始化的 state
我们也可以使用 es6 的函数参数默认值来对 state 进行初始化
let store = Redux.createStore( (state = [], action) => {
// ...
} )
通过 getState 方法,可以获取 Store 中的 state
store.getState();
通过 dispatch 方法,可以提交更改。这个方法的调用间接的调用了reducer纯函数
每次调用dispath()方法,就会去执行todo纯函数,然后把上一次的state数据作为参数传给todo函数,然后把dispatch()方法中的对象传给todo纯函数的action对象
store.dispatch({
type: 'ADD',
payload: 'MT'
})
action 是一个对象,用来在 dispatch 的时候传递动作和数据,我们在实际业务中可能会中许多不同的地方进行同样的操作,这个时候,我们可以创建一个函数用来生成(返回)action对象。
function add(payload) {
return {
type: 'ADD',
payload
}
}
store.dispatch(add('MT'));
store.dispatch(add('Reci'));
...
可以通过 subscribe 方法注册监听器(类似事件),每次 dispatch action 的时候都会执行监听函数,该方法返回一个函数,通过该函数可以取消当前监听器
let unsubscribe = sotre.subscribe(function() {
console.log(store.getState());
});
unsubscribe();
Redux核心概念中各方法使用示例及详细解释:
Redux
工作流解析:
当一个应用比较复杂的时候,状态数据也会比较多,如果所有状态都是通过一个 Reducer 纯函数来进行修改(增删改查)的话,那么这个 Reducer 就会变得特别复杂。这个时候,我们就会对这个 Reducer 进行必要的拆分
let datas = {
user: {},
items: []
cart: []
}
我们把上面的 users、items、cart 进行分拆
// user reducer
function user(state = {}, action) {
// ...
}
// items reducer
function items(state = [], action) {
// ...
}
// cart reducer
function cart(state = [], action) {
// ...
}
模拟 combineReducers()方式自己实现Reducer()纯函数的拆分与融合:
多种数据同时操作问题重现:
示例,如以下方法,每次操作某种数据,其他数据都必须跟着改变:
模拟实现combineReducers()拆分融合函数——问题重现
问题:每种数据进行更改时,必然会涉及到其他数据的控制,当不小心忘记或错该其他数据时,会造成报错或其他错误。
解决:
模拟实现combineReducers()拆分融合函数——问题重现
使用Redux中自带的combineReducers()方法原理和以上基本一致,只是会有一些优化。
该方法的作用是可以把多个 reducer 函数合并成一个 reducer。
注意:
let reducers = Redux.combineReducers({
user,
items,
cart
});
let store = createStore(reducers);
使用combineReducers()方法完整代码实现:
模拟实现combineReducers()拆分融合函数——问题重现
再次强调的是,redux 与 react 并没有直接关系,它是一个独立的 JavaScript 状态管理库,如果我们希望中 React 中使用 Redux,需要先安装 react-redux。
npm i -S redux react-redux
// ./store/reducer/users.js
let users = [{
id: 1,
username: 'baoge',
password: '123'
},
{
id: 2,
username: 'MT',
password: '123'
},
{
id: 3,
username: 'dahai',
password: '123'
},
{
id: 4,
username: 'zMouse',
password: '123'
}];
export default (state = users, action) => {
switch (action.type) {
default:
return state;
}
}
// ./store/reducer/items.js
let items = [
{
id: 1,
name: 'iPhone XR',
price: 542500
},
{
id: 2,
name: 'Apple iPad Air 3',
price: 377700
},
{
id: 3,
name: 'Macbook Pro 15.4',
price: 1949900
},
{
id: 4,
name: 'Apple iMac',
price: 1629900
},
{
id: 5,
name: 'Apple Magic Mouse',
price: 72900
},
{
id: 6,
name: 'Apple Watch Series 4',
price: 599900
}
];
export default (state = items, action) => {
switch (action.type) {
default:
return state;
}
}
// ./store/reducer/cart.js
export default (state = [], action) => {
switch (action.type) {
default:
return state;
}
}
// ./store/index.js
import {createStore, combineReducers} from 'redux';
import user from './reducer/user';
import users from './reducer/users';
import items from './reducer/items';
import cart from './reducer/cart';
let reducers = combineReducers({
user,
users,
items,
cart
});
const store = createStore(reducers);
export default store;
想在 React 中使用 Redux ,还需要通过 react-redux 提供的 Provider 容器组件把 store 注入到应用中
// index.js
import {Provider} from 'react-redux';
import store from './store';
ReactDOM.render(
,
document.getElementById('root')
);
有了 connect 方法,我们不需要通过 props 一层层的进行传递, 类似路由中的 withRouter ,我们只需要在用到 store 的组件中,通过 react-redux 提供的 connect 方法,把 store 的state数据注入到组件的 props 中,其他组件使用时才能通过this.props获得注入的store仓库。
import {connect} from 'react-redux';
class Main extends React.Component {
render() {
console.log(this.props);
}
}
export default connect()(Main);
默认情况下,connect 会自动注入 dispatch 方法
connect()方法简单原理:
function connect(callback){
return function(Component){
//执行过程中会调用callback函数,然后获取User组件中的数据id:1
let obj = callback(store.state);
for(let k in obj){
//然后把获得的数据注入到组件的props属性中
Component.props[k] = obj[k];
}
}
}
connect(function(state){
return {
id:1
}
})(User)
6.3.1注入 state 到 props
export default connect( state => {
return {
items: state.items
}
} )(Main);
connect 方法的第一个参数是一个函数
store.getState()
this.props.items
使用react-redux完整代码示例(只注入users数据):
React 中使用 Redux步骤分析(**):
App.js:引入根级组件BaseApp
import React from 'react';
import './App.css';
import BaseApp from './components/BaseApp';
function App() {
return (
);
}
export default App;
BaseApp.js:路由页面;获取创建好的仓库;通过Provider将仓库数据注入到整个组件
import React from 'react';
import { BrowserRouter as Router, Link, Route } from 'react-router-dom';
import User from '../views/User';
import { Provider } from 'react-redux';
import store from '../store/createStore';
/**
* 用于路由各个页面
*/
class BaseApp extends React.Component {
render() {
return (
{/* 使用Provider组件可以将store数据注入整个应用 */}
User
);
}
}
export default BaseApp;
createStore.js:调用融合函数,且调用纯函数(注意纯函数的实现方式和初始值的传递);创建仓库
//引入Redux相关方法createStore和combineReducers(React中不能直接引入Redux)
import { createStore, combineReducers,dispatch } from 'redux';
// import users from '../data/users';
import users from '../data/users';
import items from '../data/items';
//调用融合函数,并创建仓库
let reducer = combineReducers({
users,
items
});
//注意要在此处给初始化数据的话,因为combineReducers函数中初始化了数据为{},所以需要在调用dispatch()且调用store.getState()后才能获得数据
// 但如果直接在combineReducers()给出初始化数据,首次创建时就能获取store数据
let store = createStore(reducer);
export default store;
users.js:实现纯函数和初始数据的传递(注意纯函数的实现及导出;初始化数据方式)
let users = [{
id: 1,
username: 'baoge',
password: '123'
},
{
id: 2,
username: 'MT',
password: '123'
},
{
id: 3,
username: 'dahai',
password: '123'
},
{
id: 4,
username: 'zMouse',
password: '123'
}];
//使用箭头函数直接导出函数,将users作为初始化数据传入,创建仓库后直接获取
//使用箭头函数直接导出函数,将users作为初始化数据传入,创建仓库后直接获取
export default (state = users, action)=>{
switch (action.type) {
case 'USER_ADD':
return [...state.users,action.payload]
default:
return state;
}
}
User.js:用户组件的显示(注意connect()()方法的使用,及方法内state数据的注入)
import React from 'react';
import { connect } from 'react-redux';
class User extends React.Component{
render(){
console.log(this.props.users);
return(
{
this.props.users.map(user=>{
return - #{user.username}/{user.password}
})
}
);
}
}
// 该函数的第一个参数就是 store 中的 state : store.getState()
// 该函数的返回值将被解构赋值给 props : this.props.items
export default connect(state=>{
return {
users:state.users
}
})(User);
效果:
当需要新增用户时:
users.js纯函数中:
let idMax = 4;
//使用箭头函数直接导出函数,将users作为初始化数据传入,创建仓库后直接获取
export default (state = users, action)=>{
switch (action.type) {
case 'USER_ADD':
//每次增加时idMax需不同,可以在每次调用时将idMax+1
return [...state,{id:++idMax,...action.payload}]
default:
return state;
}
}
User.js:
import React from 'react';
import { connect } from 'react-redux';
class User extends React.Component{
constructor(props){
super(props);
this.addUser = this.addUser.bind(this);
//通过ref属性的createRef()获取用户名
this.username = React.createRef();
}
addUser(){
let {value} = this.username.current;
//判断value不为空时,新增
if(value!==""){
let {dispatch} = this.props;
dispatch({
type:'USER_ADD',
payload:{
username:value,
password:'888888'
}
});
}
}
render(){
// let idMax = 4;
return(
用户名:
{
this.props.users.map(user=>{
return - #{user.username}/{user.password}
})
}
);
}
}
// 该函数的第一个参数就是 store 中的 state : store.getState()
// 该函数的返回值将被解构赋值给 props : this.props.items
export default connect(state=>{
return {
users:state.users
}
})(User);
效果:
为了能够更加方便的对 redux 数据进行观测和管理,我们可以使用 Redux DevTools extension 这个浏览器扩展插件
安装指引:https://github.com/zalmoxisus/redux-devtools-extension
浏览器中加载插件:扩展程序--》开启开发者模式--》加载插件
代码调用:安装完插件后,只需要在创建仓库方法createStore()的第二个参数加上window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
效果:打开浏览器开发者工具面板 -> redux
许多时候,我们的数据是需要和后端进行通信的,而且在开发模式下,很容易就会出现跨域请求的问题,好在 create-react-app 中内置了一个基于 node 的后端代理服务,我们只需要少量的配置就可以实现跨域
相对比较的简单的后端 URL 接口,我们可以直接中 package.json 文件中进行配置
注意: 设置"proxy": "http://localhost:8989"的位置在最外层。
// 后端接口
http://localhost:8989/api/getUser
// http://localhost:3000
{
"proxy": "http://localhost:8989"
}
axios({
url: '/api/getUser'
});
package.json 配置方式完整示例:
后端:安装npm i -S koa koa-router;并建立基于 node 的后端应用服务器参考;
Background.js:
/**
* 使用node环境及koa框架建立后台服务器
*/
//注意import是ES6语法,如果想直接在node环境下运行该文件需要安装babel编译,否则会报错。可以使用require()语法即可
// const Koa = require("Koa");
// const Router = require("koa-router");
// const users = require('../data/users.js');
import Koa from 'koa';
import Router from 'koa-router';
import koaBody from 'koa-body';
import users from './userData';
//注意此处不能使用const声明
let app = new Koa();
let router = new Router();
console.log(users);
app.use(koaBody({
multipart:true
}));
router.get("/getUser",ctx=>{
console.log(users);
ctx.body = users;
});
app.use(router.routes());
app.listen("8989",function(){
console.log("8989服务器已开启。。。。。。。");
});
userData.js数据:将users数据单独提取出来
let users = [{
id: 1,
username: 'baoge',
password: '123'
},
{
id: 2,
username: 'MT',
password: '123'
},
{
id: 3,
username: 'dahai',
password: '123'
},
{
id: 4,
username: 'zMouse',
password: '123'
},
{
id: 5,
username: 'zMouse2',
password: '123'
}];
export default users;
后台通过localhost:8989/getUser能获取到数据即为成功
更改纯函数:增加获取数据方法USER_GET
user_async.js:
let idMax = 5;
//使用箭头函数直接导出函数,将users作为初始化数据传入,创建仓库后直接获取
export default (state = [], action)=>{
console.log(action.payload);
switch (action.type) {
case 'USER_GET':
//注意此处直接将所有数据返回,所以不用解构原来的state
return action.payload;
case 'USER_ADD':
//每次增加时idMax需不同,可以在每次调用时将idMax+1
return [...state,{id:++idMax,...action.payload}]
default:
return state;
}
}
componentDidMount()函数:通过生命周期函数componentDidMount()函数,并安装axios (npm i -S axios)发送异步请求获取数据;通过axios发送异步请求;并将请求到的数据通过dispatch方法更新到前端页面。
前端组件User_async.js:
import React from 'react';
import { connect } from 'react-redux';
// 引入axios发送异步请求
import axios from 'axios';
class User extends React.Component{
constructor(props){
super(props);
this.addUser = this.addUser.bind(this);
//通过ref属性的createRef()获取用户名
this.username = React.createRef();
}
addUser(){
let {value} = this.username.current;
//判断value不为空时,新增
if(value!==""){
let {dispatch} = this.props;
dispatch({
type:'USER_ADD',
payload:{
username:value,
password:'888888'
}
});
}
//清空输入框
this.username.current.value = '';
}
//通过发送异步请求获取数据,React发送异步请求在componentDidMount()方法,使用axios发送异步请求到后端
// 注意:需要使用异步async和await
async componentDidMount(){
let rs = await axios({
//package.json中加上 "proxy": "http://localhost:8989"
url:'/getUser'
// 当前端和后台系统请求地址需要使用/api进行区分时,使用proxy
//url:'/api/getUser'
});
//获取数据后,通过dispatch将数据进行显示USER_GET
let {dispatch} = this.props;
dispatch({
type:'USER_GET',
payload:rs.data
});
}
render(){
return(
用户名:
{
this.props.users.map(user=>{
return - #{user.username}/{user.password}
})
}
);
}
}
// 该函数的第一个参数就是 store 中的 state : store.getState()
// 该函数的返回值将被解构赋值给 props : this.props.items
export default connect(state=>{
return {
users:state.users
}
})(User);
package.json配置:两种方式解决跨域问题:package.json(简单跨域)和./src/setupProxy.js 配置(相对复杂)
package.json中加上 "proxy": "http://localhost:8989"即可
create-react-app脚手架低于2.0版本时候,可以使用对象类型,但是最新的create-react-app脚手架2.0版本以上只能配置string类型,否则会报错。因此针对相对复杂的情况,可以有更多的配置时,使用setupProxy.js文件配置。
"proxy":{
"/api/**":{
"target":"http://localhost:8989",
"changeOrigin": true
}
}
针对相对复杂的情况,可以有更多的配置时,使用setupProxy.js文件配置。在项目src目录项,建立setupProxy.js文件,并安装http-proxy-middleware代理服务器。
npm i -S http-proxy-middleware
如:前端和后端请求地址通过是否有/api 进行区分
http-proxy-middleware版本问题:针对http-proxy-middleware的官方文档,发现最新的1.0.0版本已经对模块的引用作了明确的要求 (参考自https://blog.csdn.net/balics/article/details/104479641)
0.x.x版本的引用方式 const proxy = require('http-proxy-middleware');
// setupProxy.js
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
proxy('/api', {
target: 'http://localhost:8989/',
//重新路径,即去掉/api后再发起请求
pathRewrite: {
'^/api': ''
}
})
);
};
1.0.0版本的引用方式 const { createProxyMiddleware } = require('http-proxy-middleware');
// setupProxy.js
//http-proxy-middlewar 1.0.0版本使用
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app){
app.use('/api', createProxyMiddleware({ target: 'http://localhost:8989/', changeOrigin: true ,
secure: false,
pathRewrite: {
'^/api': ''
} }));
}
注意:如果报以下报错就是http-proxy-middleware引用方式错误
其他代码通配置package.json方式,只是前端页面使用/api/getUser区分URL即可
async componentDidMount(){
let rs = await axios({
//package.json中加上 "proxy": "http://localhost:8989"
// url:'/getUser'
// 当前端和后台系统请求地址需要使用/api进行区分时,使用proxy
url:'/api/getUser'
});
//获取数据后,通过dispatch将数据进行显示USER_GET
let {dispatch} = this.props;
dispatch({
type:'USER_GET',
payload:rs.data
});
}
默认情况下,dispatch 是同步的,我们需要用到一些中间件来处理。
中间件使用场景:redux是将数据存储在内存中,因此每次页面刷新后,存在内存中的数据就没有了,再想对原始数据进行操作就不行了。如,想要在每次刷新时,都将原来数据同步存储在本地存储中,如果单纯使用dispatch()方法就无法实现,于是就可以使用中间件进行处理进行数据持久化。
例如,koa框架的异步:
const logger = store => next => action => {
console.group(action.type)
console.info('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
console.groupEnd(action.type)
return result
}
模拟redux.applyMiddleware()方法实现中间件同样功能(在更改数据的同时,打印日志)(以下示例使用combineReducers()完整实现代码基础上进行更改测试):
需求:只要调用dispatch()方法都打印一下日志
原理分析:
模拟中间件代码实现:以使用combineReducers()实现拆分与融合完整代码为例,只需要将store.dispatch()包装到自己的myDispatch()方法中,并加入打印日志功能,在调用时使用自定义的myDispatch()方法即可。
//自己写方法实现中间件(在更改数据的同时,打印日志)
function myDispatch(action){
store.dispatch(action);
console.log(store.getState());
}
//第一次只更改users
myDispatch(updateUser({ id: 1, username: 'MT' }));
//第二次增加items
myDispatch(addItem({ id: 1, name: 'Ipad', price: '$5000' }));
myDispatch(addItem({ id: 2, name: 'Iphone', price: '$6000' }));
// 第三次删除items
myDispatch(removeItem(2));
// 第四次增加carts
myDispatch(addCart({ id: 1, name: 'book', price: '$5000' }));
myDispatch(addCart({ id: 2, name: 'Iphone', price: '$6000' }));
// 第五次删除carts
myDispatch(removeCart(1));
问题:以上代码能使用中间件的功能,如果在使用过程中,使用到了dispatch(),就写了第三方类库方法去包装dispatch()方法,用到了其他redux方法或其他框架都如此进行调用,则使用的类库和方法就会乱套,每个人都定义自己的。
那么如何做到,所有的方法包装过后不用更改任何代码,就能实现自己的其他功能?
解决:可以先将原来的方法store.dispatch()通过变量存下来,再把自己增加功能的方法赋值给原来的方法(此时该方法已改变可通过变量进行调用),并在方法中通过变量调用存下来的方法处理原有的操作。这样用户在真正调用store.dispatch()方法时,仍然和之前操作一样就可以实现附加功能:
//先将原本的store.dispatch方法通过变量进行存储
let myDispatch = store.dispatch;
//再将加入自定义功能的方法赋值给原来的方法store.dispatch,此时原本的方法就包含有自定义功能(如打印日志)
store.dispatch = function(action){
//在方法中调用存储下来的方法,完成原本store.dispatch的应有功能
myDispatch(action);
console.log(store.getState());
}
完整代码实现:发现同样实现数据的更改,且添加了打印日志的功能,却不需要在调用dispatch()方法时做修改即可做到。
//自己写方法实现中间件(在更改数据的同时,打印日志)
let myDispatch = store.dispatch;
store.dispatch = function (action) {
console.log("-----------------------------");
console.log("更改数据前:", store.getState());
myDispatch(action);
console.log("更改数据后:", store.getState());
console.log("-----------------------------");
}
redux.applyMiddleware()使用原理和模拟相似,只是逻辑和功能更加复杂。
通过 applyMiddleware 方法,我们可以给 store 注册多个中间件
注意:devTools 的使用需要修改一下配置。即使用代码版,而不是通过windows进行调用。
npm i -D redux-devtools-extension
...
import { composeWithDevTools } from 'redux-devtools-extension';
...
const store = createStore(
reducres,
composeWithDevTools(
applyMiddleware( logger )
)
)
使用redux-chunk中间件必要性:
不使用redux-chunk中间件问题重现:使用异步函数包装方式,实现不用多次调用即可多次异步发送请求。即将axios发送请求和dispatch函数进行统一封装成action函数。
import axios from 'axios';
export function selectUser(payload){
return async dispatch=>{
let rs = await axios({
url:'/api/getUser'
});
dispatch({
type:'USER_GET',
payload:rs.data
});
}
}
//模拟实现chunk
let {dispatch} = this.props;
dispatch(selectUser());
发现会报错:
npm i -S redux-chunk
不同版本redux-chunk使用方法不同:
低版本下:
import {createStore, combineReducers, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import user from './reducer/user';
import items from './reducer/items';
import cart from './reducer/cart';
let reducers = combineReducers({
user,
items,
cart
});
const store = createStore(
reducers,
composeWithDevTools(applyMiddleware(
thunk
))
);
高版本下(此处1.0.11):
//引入Redux相关方法createStore和combineReducers(React中不能直接引入Redux)
import { createStore, combineReducers, applyMiddleware } from 'redux';
//测试异步时数据从后端获取,但是纯函数还需要使用
// import users from '../data/users';
import users from '../data/users_async';
import items from '../data/items';
// 引入redux-chunk的applyMiddleware 方法
// import chunk from 'redux-chunk';
import { middleware as apiMiddleware } from 'redux-chunk';
//调用融合函数,并创建仓库
let reducer = combineReducers({
users,
items
});
//注意要在此处给初始化数据的话,因为combineReducers函数中初始化了数据为{},所以需要在调用dispatch()且调用store.getState()后才能获得数据
// 但如果直接在combineReducers()给出初始化数据,首次创建时就能获取store数据
const store = createStore(
reducer,
// window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
applyMiddleware(apiMiddleware)
);
export default store;
高版本下使用地方版方式会报错:
使用redux-chunk进行异步发送请求时,要使用redux-devtools-extension插件需要安装且引入redux-devtools-extension 。
npm i -S redux-devtools-extension
//引入Redux相关方法createStore和combineReducers(React中不能直接引入Redux)
import { createStore, combineReducers, applyMiddleware } from 'redux';
//测试异步时数据从后端获取,但是纯函数还需要使用
// import users from '../data/users';
import users from '../data/users_async';
import items from '../data/items';
// 引入redux-chunk的applyMiddleware 方法
// import chunk from 'redux-chunk';
// 高版本redux-chunk引入方式,且要使用redux-devtools-extension插件需要引入
import { middleware as apiMiddleware } from 'redux-chunk';
import {composeWithDevTools} from 'redux-devtools-extension';
//调用融合函数,并创建仓库
let reducer = combineReducers({
users,
items
});
//注意要在此处给初始化数据的话,因为combineReducers函数中初始化了数据为{},所以需要在调用dispatch()且调用store.getState()后才能获得数据
// 但如果直接在combineReducers()给出初始化数据,首次创建时就能获取store数据
const store = createStore(
reducer,
// window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
composeWithDevTools(applyMiddleware(apiMiddleware))
// applyMiddleware(chunk)
);
export default store;