不要问你到底需不需要用这个redux,你直接用上就对了,不要怕
概念性的东西就不解释了,参考中文文档:https://www.redux.org.cn/,
那你可能会说了,我要是文档都看懂了,我还看博客干啥?的确是这样,这个文档有些地方确实难理解,它不跟vuex一样,看一遍就能理解个70%,再随便找些教程,就能开撸代码了,但关于这个redux,你有时候看好多博客说明,一上来就是先来个计数器例子,创建一个redux文件夹,在这个文件夹下创建几个文件,然后安装一堆依赖,可最后你看完后,一脸蒙蔽,这是啥?不是就用一个redux吗 ,怎么折腾了那么多东西,才能跑起来,哎!真难!,抱怨一圈,日子待过,代码还是待撸啊,我用例子解释以下redux是怎么一步步使用的,后边会用一个小例子说下redux怎么配合接口玩,不知道怎么配合接口还玩个啥子呦!
redux晦涩难懂,你多写几遍就懂了,因为它的写法很固定
Redux 核心概念 (个人理解)
Store : 数据仓库,简单说,就是以前我们写在react组件中state中的数据
Action: 行为/动作,用它的地方是在调接口数据,或者用户的点击操作,需要使用dispatch方法提交,
(dispatch(action)dispatch就是分发事件,不理解先放放
Reduce: 一个纯函数,具体有多纯,这么来说吧,固定的输入产生固定的输出, 它的作用是给你返回一个新
的state,来更新视图,接收两个参数(state,action)
Type: 类型 一般会单独抽离出来,语法就是一个常量,这个type是你提交action时必须要带的
东西,它会在reduce里来用这个type匹配给你返回什么样的state
单一数据流
**
计数器例子 点击加1 ,点击减1 ,先从最简单的说 这里只使用redux 配合react,慢慢说后边的 redux-react
还有中间件,以及配合调试工具是什么东西
**
希望你多写几个demo,只看关于它的教程,想快速上手而不自己写写还是没有啥用的
新建项目 npx create-react-app react-redux
vacode 打开项目,删除src下的所有目录,我们来自己新建,只留下index和App,一般开发中会单独做一个文件夹放redux的东西,让项目结构清晰,这个我们一步步拆分
index.js
import React from 'react';
import {render} from 'react-dom';
import App from "./App";
render(<App />, document.getElementById('root'));
App.js
import React, { Component } from 'react'
export class App extends Component {
state = {
count: 0
}
render() {
const { count} = this.state
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button>点击增加</button>
<button>点击减少</button>
<button>延时1秒增加</button>
</div>
)
}
}
export default App;
运行 npm start (这里逻辑就是根据选择的数据,点击按钮操作后渲染视图)
项目目录
给按钮添加点击事件,获取选中的下拉框的值
改造App.js
import React, { Component } from 'react'
export class App extends Component {
state = {
count: 0
}
render() {
const { count } = this.state
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
)
}
// 点击增加
increment = () => {
// 获取选中的下拉框的值 这里乘1,是因为得到的值是String类型
// let number = Number(this.select.value)
let number = this.select.value * 1
// 加法计算
let count = this.state.count + number;
// 更新 state的值
this.setState({ count })
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 减计算
let count = this.state.count - number;
// 更新 state的值
this.setState({ count })
}
// 异步操作延时加1
incrementAsync = () => {
setTimeout(() => {
let number = this.select.value * 1
// 加法计算
let count = this.state.count + number;
// 更新 state的值
this.setState({ count })
}, 1000)
}
}
export default App
引入redux 处理计数器
npm i redux -S 或者yarn add redux -S
为了项目结构的清晰,修改src文件夹的目录,新建redux文件夹,这个文件下的自文件干什么的 ,看注释啊,不是有type --reducer–action–store嘛,先写type 和reducer
index.js
import React from 'react';
import { render } from 'react-dom';
import App from "./App";
/**
* 引入 createStore方法 从redux ,用于创建 store
* createStore()方法接收第一个参数是reducer
**/
import { createStore } from 'redux'
// 引入reducer,因为当前只有一个函数,先采用解构方法引入
import { counter } from './redux/reducers'
// 将 reducer作为参数 传入 createStore()方法
const store = createStore(counter)
render(<App store={store}/>, document.getElementById('root'));
action-type.js
/**
* 包含多个被提交的action的类型 常量 值为大写或者小写的字符串
*/
// 点击增加
export const INCUREMENT = "INCUREMENT";
// 点击减去
export const DECUREMENT = "DECUREMENT";
// 延时增加
export const INCUREMENTASYNC = "INCUREMENTASYNC";
reducers.js
/**
* 包含多个reduce 函数
* reducer (Function): 接收两个参数,分别是当前的 state 和要处理的 action,返回新的state 。
*/
/**
* 计数器,一个纯函数接收两个参数
* @param {*} state 初始值,数据类型可以是引用也可以基本数据
* @param {*} action 是个对象,必须有一个是type且必传,payload为参数,可选的
* 你在action 里 提交的必须是这样的 {type:"type",payload:可选}
*/
export function counter(state = 0, action) {
switch (action.type) {
default:
return state;
}
}
此时刷新页面,没有报错,在index.js中打印 store 变量,会看到控制台打印
此时还没有使用redux来存储数据,还是使用的组件中的state,那下边接着改造,将App 组件中的state 的数据存储到redux 中,其实也就是在reducer中,还记得reducer接收两个参数吗,一个state,一个action
其中第一个state就是初始值,因为默认在app组件中点击了 0 次,所以这里就是初始值为0 ,下边接着改造,既然将组件中的state值放到了reducer中,那么App组件的state就不要了
App.js
还记得上边在index.js中打印的那个store变量不是有个getState吗,就是使用 this.props.store.getState() 来获取值,也就是原先使用this.state获取初始值的方式,都要换成this.props.store.getState() 这种方式,因为state没有了,此时this.setState()页可以删除了
import React, { Component } from 'react'
export class App extends Component {
render() {
const count = this.props.store.getState()
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
)
}
// 点击增加
increment = () => {
// 获取选中的下拉框的值 这里乘1,是因为得到的值是String类型
// let number = Number(this.select.value)
let number = this.select.value * 1
// 加法计算
let count = this.props.store.getState() + number;
// 更新 state的值
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 减计算
let count = this.props.store.getState() - number;
// 更新 state的值
}
// 异步操作延时加1
incrementAsync = () => {
setTimeout(() => {
let number = this.select.value * 1
// 加法计算
let count = this.props.store.getState() + number;
// 更新 state的值
}, 1000)
}
}
export default App
接着刷新页面,打开控制台,没有任何报错,但是你会发现此时的点击事件失效了,这是因为还有一个东西没有用,就是最后的action,操作页面出发点击事件,是一个行为吧,此时就需要你使用dispatch()方法分发这个事件到reducer里,然后reducer会给你返回一个新的state
接着改造
App.js
还记得控制台打印store的时候有个dispatch方法吗
此时在点击事件中改变 state的值就需要通过dispatch({type:类型,参数})
之所以传type 是因为在reducer里需要用type来匹配你这里分发的事件的type,根据这个type来决定返回什么样的state
this.props.store.dispatch({type:INCUREMENT,count})
来改变初始值,注意啊,action有同步的还有异步的,这里说的都是同步的,redux本身只能同步
import React, { Component } from 'react'
import { INCUREMENT,DECUREMENT } from "./redux/action-type";
export class App extends Component {
render() {
const count = this.props.store.getState()
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
)
}
// 点击增加
increment = () => {
// 获取选中的下拉框的值 这里乘1,是因为得到的值是String类型
let number = this.select.value * 1
this.props.store.dispatch({type:INCUREMENT,number})
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 更新 state的值
this.props.store.dispatch({type:DECUREMENT,number})
}
// 异步操作延时加1
incrementAsync = () => {
let number = this.select.value * 1
setTimeout(() => {
this.props.store.dispatch({type:INCUREMENT,number})
}, 1000)
}
}
export default App
此时在 reducers.js中 打印 console.log(state,action) ,打开控制台会看到
接着修改reducer.js
因为action 传了type,所以在reducer里也需要用type来区分你的事件
你可以用switch,也可以用if - else,不管用什么,最后一定要return 一个新的state
import { INCUREMENT, DECUREMENT } from "./action-type";
export function counter(state = 0, action) {
console.log(state,action)
switch (action.type) {
case INCUREMENT:
return state + action.number;
case DECUREMENT:
return state - action.number;
default:
return state;
}
}
好了,此时改造完,你又发现一个问题,视图没有更新,咋回事?打开控制台,你会发现,其实每次的值已经变化了,但是没有引起视图的更新,此时就需要用到监听了
将原有的render函数二次封装成高阶函数 ,然后通过redux 提供的 subscribe() 方法,进行监听更新
import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import App from './App'
// 引入reducer,因为当前只有一个函数,先采用解构方法引入
import { counter } from './doc/reducer'
// 将 reducer作为参数 传入 createStore()方法
let store = createStore(counter)
// 函数表达式 , 返回一个函数,=> 高阶函数
const appRender = () => render(<App store={store} />, document.getElementById('root'))
appRender()
store.subscribe(appRender)
此时刷新控制台,就可以看到视图更新了
好了,一个最简单的redux使用就完了,但是action 的这种写法,官方推荐单独抽离出来,接着重新改造,将action进行抽离,创建一个actions.js
actions.js
/**
* 包含所有的action creator (是一个工厂函数)
* 必须返回一个包含type属性的对象
*/
import { INCUREMENT, DECUREMENT } from "./action-type";
// 增加的
// export const incrementCreate = function(member){
// return {
// type:INCUREMENT,
// member:member
// }
// }
// 增加的 es6 简写,返回引用数据类型时,必须是表达式的形式 否则无效
export const incrementCreate = (number) => ({ type: INCUREMENT, number })
// 减少的
export const decrementCreate = (number) => ({ type: DECUREMENT, number })
接着改造
App.js
import React, { Component } from 'react'
import { incrementCreate, decrementCreate } from "./redux/actions";
export class App extends Component {
render() {
const count = this.props.store.getState()
return (
<>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<div>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
</>
)
}
// 点击增加
increment = () => {
let number = this.select.value * 1
this.props.store.dispatch(incrementCreate(number))
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 更新 state的值
this.props.store.dispatch(decrementCreate(number))
}
// 异步操作延时加1
incrementAsync = () => {
let number = this.select.value * 1
setTimeout(() => {
this.props.store.dispatch(incrementCreate(number))
}, 1000)
}
}
export default App
既然action 进行抽离了,那么把store也单独拿出来
改造index.js
import React from 'react';
import { render } from 'react-dom';
import App from "./App";
import store from "./redux/store";
const appRender = () => render(<App store={store} />, document.getElementById('root'))
appRender()
store.subscribe(appRender)
redux文件夹下创建store.js
注意引入文件的路径
/**
* 引入 createStore方法 从redux ,用于创建 store
* createStore()方法接收第一个参数是reducer
**/
import { createStore } from 'redux'
// 引入reducer,因为当前只有一个函数,先采用解构方法引入
import { counter } from './reducers'
// 将 reducer作为参数 传入 createStore()方法
const store = createStore(counter)
console.log(store)
export default store;
好了,刷新页面,没有任何问题啊,到这里就是redux单独配合react使用,虽然代码功能实现了,但是也有很多不好的地方,比如在App.js 中,使用了 this.props.store.dispatch() 这种redux的写法,而且代码耦合度很高,而且你会发现,掺杂了好多redux的代码,看的跟react也不搭啊,那么可不可以就只用react的语法就把redux使用了,答案是当然有,这就需要引入一个插件 react-redux,有了这个插件就不用再直接使用redux的语法了,当然,你不用这个插件也是可以的啊,有的教程一上来就是引入3个东西redux —react-redux-- react-thunk,也不说为什么,,其实你现在就应该明白了,只引入redux 也是可以的,react-redux插件帮你更优化了redux配合react使用
那好,看看react-redux的使用
https://react-redux.js.org/
yarn add react-redux -S
它提供了两个重要的东西,一个Provider组件,一个connect()方法
好了,安装完成,改造
index.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import App from "./App";
import store from "./redux/store";
render((
<Provider store={store}>
<App />
</Provider>
), document.getElementById('root'));
然后在修改组件,必须使用connect进行连接
App.js
import React, { Component } from 'react'
import { incrementCreate, decrementCreate } from "./redux/actions";
import PropTypes from 'prop-types'
/**
* connect 连接 React 组件与 Redux store。 是一个函数,返回一个新的组件
* 接收几个参数,最重要的是(state,第二个是对象)
*/
import { connect } from "react-redux";
export class App extends Component {
// 验证所需要的数据的类型, 你想要就写,不想要就不写,这个不重要,重要的是最后的合并
static propTypes = {
count: PropTypes.number.isRequired,
incrementCreate: PropTypes.func.isRequired,
decrementCreate: PropTypes.func.isRequired,
}
render() {
const {count} = this.props
console.log(count);
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
)
}
// 点击增加
increment = () => {
let number = this.select.value * 1
// this.props.store.dispatch(incrementCreate(number))
this.props.incrementCreate(number)
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 更新 state的值
this.props.decrementCreate(number)
// this.props.store.dispatch(decrementCreate(number))
}
// 异步操作延时加1
incrementAsync = () => {
let number = this.select.value * 1
setTimeout(() => {
this.props.incrementCreate(number)
// this.props.store.dispatch(incrementCreate(number))
}, 1000)
}
}
export default connect(
state => ({count:state}), // 这个必须是函数
{incrementCreate,decrementCreate} // 这是个对象啊
)(App) // 这样写以后导出的就不是App组件,而是被connect包装成了一个新的组件
刷新页面,没有任何问题,打开控制台,看到App组件被包装后了
这样搞以后,你就看到在App组件中就全部都是react组件的写法了,将redux的代码都交给react-redux组件管理了,而且也不用自己做监听了,你可以参考文档将这部分进行近一步优化,react-redux文档将组件分为了两部分,一个是UI组件,这部分组件没有redux的Api,另一个就是容器组件,具体的可以看看文档,算了,再写写吧!上边意思就是让你再抽离一下代码,那就再src下再建俩文件夹呗,一个是容器组件containers ,一个是UI组件conponents,将使用redux的Api的组件放到containers文件夹下,不使用redux的api的放到components下
index.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import Count from "./containers/Count";
import store from "./redux/store";
render((
<Provider store={store}>
<Count />
</Provider>
), document.getElementById('root'));
// store.subscribe(() => render(<App store={store} />, document.getElementById('root')))
App.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class App extends Component {
// 验证所需要的数据的类型, 你想要就写,不想要就不写,这个不重要,重要的是最后的合并
static propTypes = {
count: PropTypes.number.isRequired,
incrementCreate: PropTypes.func.isRequired,
decrementCreate: PropTypes.func.isRequired,
}
render() {
const { count } = this.props
console.log(count);
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
)
}
// 点击增加
increment = () => {
let number = this.select.value * 1
// this.props.store.dispatch(incrementCreate(number))
this.props.incrementCreate(number)
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 更新 state的值
this.props.decrementCreate(number)
// this.props.store.dispatch(decrementCreate(number))
}
// 异步操作延时加1
incrementAsync = () => {
let number = this.select.value * 1
setTimeout(() => {
this.props.incrementCreate(number)
// this.props.store.dispatch(incrementCreate(number))
}, 1000)
}
}
Count.js
import { incrementCreate, decrementCreate } from "./../redux/actions";
import { connect } from "react-redux";
import App from '../components/App'
export default connect(
state => ({ count: state }), // 这个必须是函数
{ incrementCreate, decrementCreate } // 这是个对象啊
)(App) // 这样写以后导出的就不是App组件,而是被connect包装成
接着刷新,没有问题啊
接着说redux,它有一个问题,就是默认不能进行异步处理
,而在实际开发中又肯定会进行ajax请求,或者定时器这些东西
此时为了处理异步请求,就需要用到一个中间件redux-thunk
npm i redux-thunk -S
使用它,改造store.js使用redux提供的applyMiddleware方法,
store.js
/**
* 引入 createStore方法 从redux ,用于创建 store
* createStore()方法接收第一个参数是reducer
**/
import { createStore, applyMiddleware } from 'redux'
// 引入异步组件
import thunk from 'redux-thunk'
// 引入reducer,因为当前只有一个函数,先采用解构方法引入
import { counter } from './reducers'
// 将 reducer作为参数 传入 createStore()方法
const store = createStore(
counter,
applyMiddleware(thunk) // 使用中间件
)
console.log(store)
export default store;
App.js
// 异步操作延时加1, 这段注释所在的代码改写了
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class App extends Component {
// 验证所需要的数据的类型, 你想要就写,不想要就不写,这个不重要,重要的是最后的合并
static propTypes = {
count: PropTypes.number.isRequired,
incrementCreate: PropTypes.func.isRequired,
decrementCreate: PropTypes.func.isRequired,
incrementCreatorAsync: PropTypes.func.isRequired,
}
render() {
const { count } = this.props
console.log(count);
return (
<div>
<h4>点击了{count}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
</div>
)
}
// 点击增加
increment = () => {
let number = this.select.value * 1
// this.props.store.dispatch(incrementCreate(number))
this.props.incrementCreate(number)
}
// 点击减少
decrement = () => {
// 获取选中的下拉框的值
let number = this.select.value * 1
// 这里要重写
this.props.decrementCreate(number)
// this.props.store.dispatch(decrementCreate(number))
}
// 异步操作延时加1
incrementAsync = () => {
let number = this.select.value * 1
this.props.incrementCreatorAsync(number)
}
}
Counter.js
/**
* 包含所有的action creator (是一个工厂函数)
* 必须返回一个包含type属性的对象
*
*/
import { INCUREMENT, DECUREMENT } from "./action-type";
// 增加的 es6 简写,返回引用数据类型时,必须时表达式的形式 否则无效
export const incrementCreate = (number) => ({ type: INCUREMENT, number })
// 减少的
export const decrementCreate = (number) => ({ type: DECUREMENT, number })
/**
* Action 有异步的,还有同步的,异步action 一般再开发中都是调接口
* 需要您手动dispatch分发出去,参数是一个同步的action ,很凑巧,这里已经有一个同步的增加的action了
* ,如果没有的话,你需要手动先提前创建同步的tacion,但不用暴露出去,因为
* 这个同步action是为你的异步action服务的
* @param {*} number
*/
// 异步的增加
export const incrementCreatorAsync = (number) => {
return dispatch => {
setTimeout(() => {
dispatch(incrementCreate(number))
}, 1000)
}
}
接着刷新页面,没有任何问题!
调试redux数据管理
https://www.npmjs.com/package/redux-devtools-extension
npm i redux-devtools-extension
改造一个store.js
/**
* 引入 createStore方法 从redux ,用于创建 store
* createStore()方法接收第一个参数是reducer
**/
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension';
// 引入异步组件
import thunk from 'redux-thunk'
// 引入reducer,因为当前只有一个函数,先采用解构方法引入
import { counter } from './reducers'
// 将 reducer作为参数 传入 createStore()方法
const store = createStore(
counter,
composeWithDevTools(
applyMiddleware(thunk)
) // 使用中间件
)
console.log(store)
export default store;
需要安装 调试插件
好了,基本完事了,说一下跟接口怎么配合
跟接口配合的地方就在actions.js中的异步action操作中,但记住一点,先搞同步的,再搞异步的。代码演示一下
假设在reducer.js中再模拟一个reducer,用来模拟获取接口数据
当有多个reducer时,redux提供了一个合并多个小的reducer为一个大的reducer,暴露出去
import { combineReducers } from ‘redux’
/**
* 包含多个reduce 函数
* reducer (Function): 接收两个参数,分别是当前的 state 和要处理的 action,返回新的state 。
* 也就是根据老的state 和 action 产生新的state
*/
/**
* 计数器,一个纯函数接收两个参数
* @param {*} state 初始值,数据类型可以是引用也可以基本数据
* @param {*} action 是个对象,必须有一个是type且必传,payload为参数,可选的
* 你在action 里 提交的必须是这样的 {type:"type",payload:可选}
*
*/
import { INCUREMENT, DECUREMENT, BALL } from "./action-type";
import { combineReducers } from 'redux'
let initNum = 5;
// state = 0 参数默认值
function counter(state = initNum , action) {
// console.log(state, action)
switch (action.type) {
case INCUREMENT:
return state + action.number;
case DECUREMENT:
return state - action.number;
default:
return state;
}
}
// 模拟接口数据,初始化数据为空
let initArr = []
function getData(state = initArr , action) {
switch (action.type) {
case BALL:
return action.arr;
default:
return state;
}
}
export default combineReducers({
counter,
getData,
})
actions.js
首先在这里去调接口,然后把接口中拿到的数据分发给reducer,去改变初始值
/**
* 包含所有的action creator (是一个工厂函数)
* 必须返回一个包含type属性的对象
*
*/
import { INCUREMENT, DECUREMENT,BALL } from "./action-type";
// 增加的 es6 简写,返回引用数据类型时,必须时表达式的形式 否则无效
export const incrementCreate = (number) => ({ type: INCUREMENT, number })
// 减少的
export const decrementCreate = (number) => ({ type: DECUREMENT, number })
/**
* Action 有异步的,还有同步的,异步action 一般再开发中都是调接口
* 需要您手动dispatch分发出去,参数是一个同步的action ,很凑巧,这里已经有一个同步的增加的action了
* ,如果没有的话,你需要手动先提前创建同步的tacion,但不用暴露出去,因为
* 这个同步action是为你的异步action服务的
* @param {*} number
*/
// 异步的增加
export const incrementCreatorAsync = (number) => {
return dispatch => {
setTimeout(() => {
dispatch(incrementCreate(number))
}, 1000)
}
}
// 先写 获取接口信息的同步的action
const getBall = (arr)=>({type:BALL,arr})
// 模拟异步调接口
export const basketAsync = () => {
return dispatch => {
// 模拟调接口,最后得到的数据
const arr = [
{ name:'足球',des:'我不会玩' },
{ name:'羽毛球球',des:'真好打不懂啊' }
]
setTimeout(() => {
dispatch(getBall(arr))
}, 2000)
}
}
actions-type.js
/**
* 包含多个被提交的action的类型 常量 值为大写或者小写的字符串
*/
// 点击增加
export const INCUREMENT = "INCUREMENT";
// 点击减去
export const DECUREMENT = "DECUREMENT";
// 延时增加
export const INCUREMENTASYNC = "INCUREMENTASYNC";
export const BALL = "BALL";
Counter.js
import { incrementCreate, decrementCreate, incrementCreatorAsync, basketAsync } from "./../redux/actions";
import { connect } from "react-redux";
import App from '../components/App'
export default connect(
state => ({ obj: state }), // 这个必须是函数
{ incrementCreate, decrementCreate, incrementCreatorAsync, basketAsync } // 这是个对象啊
)(App) // 这样写以后导出的就不是App组件,而是被connect包装成
App.js
这个还是在componentDidMount这个钩子离调接口,你可以多打印一下
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class App extends Component {
// 验证所需要的数据的类型, 你想要就写,不想要就不写,这个不重要,重要的是最后的合并
static propTypes = {
obj:PropTypes.object.isRequired,
incrementCreate: PropTypes.func.isRequired,
decrementCreate: PropTypes.func.isRequired,
incrementCreatorAsync: PropTypes.func.isRequired,
}
componentDidMount(){
this.props.basketAsync();
// console.log(this.props)
}
render() {
const { counter,getData } = this.props.obj
// console.log(getData);
return (
<div>
<h4>点击了{counter}次</h4>
<br />
<select ref={select => this.select = select}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>点击增加</button>
<button onClick={this.decrement}>点击减少</button>
<button onClick={this.incrementAsync}>延时1秒增加</button>
<div>
<h4>模拟接口数据</h4>
{
getData.map((k,v)=>{
return (
<li key={v}>{k.name}</li>
)
})
}
</div>
</div>
)
}
// 点击增加
increment = () => {
let number = this.select.value * 1
this.props.incrementCreate(number)
}
// 点击减少
decrement = () => {
let number = this.select.value * 1
this.props.decrementCreate(number)
}
incrementAsync = () => {
let number = this.select.value * 1
this.props.incrementCreatorAsync(number)
}
}
刷新两秒后,显示模拟的接口数据