当前位置:网站首页>Redux求和案例详解版教程
Redux求和案例详解版教程
2022-07-23 18:05:00 【蜡笔雏田学代码】
接着上篇文章结尾 用原生react版实现了求和案例
接下来分三个版本介绍运用redux实现求和案例的过程.
感兴趣的小伙伴一起来看看吧~

使用redux编写应用
案例需求
求和案例:
有五个按钮,下拉按钮选择加数,点击加号或减号按钮,将当前求和数与下拉选择的数进行运算,得到当前的求和数,“当前求和为奇数”按钮表示当前求和为奇数时进行加法运算,“异步加”按钮表示等待0.5s再进行加法运算
效果:

redux精简版本写法(不使用action相关API)
安装redux:
npm add redux
根据原理图,我们需要写store对象和reducer函数这两个核心概念。
src=> redux文件夹=> store.js:
/* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */
// 引入createStore,专门用于创建redux中最为核心的store对象
import {
legacy_createStore as createStore } from 'redux';
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 暴露store
export default createStore(countReducer)
src=> redux文件夹=> count_reducer.js:初始化状态 和加工状态
/* 1.该文件用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数 2.reducer函数会接收到两个参数,分别为:之前的状态(preState),动作对象(action) */
// 初始化state
const initState = 0
// preState = initState :es6语法,给形参prevState赋初始值
export default function countReducer(preState = initState, action) {
// 从action对象中获取:type,data
const {
type, data } = action
// 根据type决定如何加工数据
switch (type) {
case 'increment': //如果是加
return preState + data
case 'decrement': //如果是减
return preState - data
default:
return preState
}
}
写完了上面两个核心概念的代码,接下来回到Count组件修改代码,由于组件中状态交给了redux管理,所以组件自身的state里不需要存储count值了。
如何展示初始值?
由于状态已经交给了redux管理,redux交给了store管理,所以得调用store对象。
先引入store:
import store from '../../redux/store'
使用一个getState()方法得到初始值状态:
<h1>当前求和为:{
store.getState()}</h1>
如何实现加法效果?
由于组件自身状态没有count值了,所以不能用this.setState()的方法更新状态了。
我们要通知redux加上获取到用户点击的value值,使用store身上的dispatch()方法,传入一个action对象,type为increment,data为value*1。
store.dispatch({
type: 'increment', data: value * 1 })
但是问题来了!页面并没有达到我们想要的效果,点击加按钮,并没有任何变化。
所以我们可以通过打印的方式,每次点击加按钮时,判断preState有没有增长。

打印结果:

从打印结果可以看出,每次点击加号时,preState的值都在增长,但是页面始终不变,说明状态的改变并没有渲染到页面上。redux只是维护管理状态,改完状态默认不会引起页面的更新。
所以我们要监测redux里的状态,如果redux里的状态发生了改变,我们就自己调用render(),更新页面。
如何监测redux状态的变化?
当组件一挂载到页面时,就监测redux状态的变化,只要变化了,就调用render()。
使用store身上的subscribe()方法:该方法接收一个回调函数,只要reudx里保存的任何一个状态发生改变,就调用该回调。在回调函数里调用this.setState({}),只要调用了,就会重新渲染更新页面。
componentDidMount() {
// 检测redux中状态的变化,只要变化,就调用render
store.subscribe(() => {
// 只要reudx里保存的任何一个状态发生改变,就调用该回调
// console.log('@')
this.setState({
})
})
}
Count组件=> index.jsx:
import React, {
Component } from 'react'
// 引入store,用于获取redux中保存的状态
import store from '../../redux/store'
export default class Count extends Component {
componentDidMount() {
// 检测redux中状态的变化,只要变化,就调用render
store.subscribe(() => {
// 只要reudx里保存的任何一个状态发生改变,就调用该回调
// console.log('@')
this.setState({
})
})
}
// 加法
increment = () => {
// 获取用户输入
const {
value } = this.selectNumber
store.dispatch({
type: 'increment', data: value * 1 })
}
// 减法
decrement = () => {
// 获取用户输入
const {
value } = this.selectNumber
store.dispatch({
type: 'decrement', data: value * 1 })
}
// 奇数再加
incrementIfOdd = () => {
// 获取用户输入
const {
value } = this.selectNumber
// 读取原来的状态值
const count = store.getState()
if (count % 2 !== 0) {
store.dispatch({
type: 'increment', data: value * 1 })
}
}
// 异步加
incrementAsync = () => {
// 获取用户输入
const {
value } = this.selectNumber
setTimeout(() => {
store.dispatch({
type: 'increment', data: value * 1 })
}, 500)
}
render() {
return (
<div>
<h1>当前求和为:{
store.getState()}</h1>
<select ref={
c => this.selectNumber = c}>
<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.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={
this.incrementAsync}>异步加</button>
</div>
)
}
}
总结求和案例_redux精简版:
1️⃣ 去除Count组件自身的状态
2️⃣ src下建立:
-src
-redux
-store.js
-count_reducer.js
3️⃣
store.js:1).引入redux中的createStore函数,创建一个store
2).createStore调用时要传入一个为其服务的reducer
3).记得暴露store对象
4️⃣
count_reducer.js:1).reducer的本质是一个函数,接收:preState,action,返回:加工后的状态
2).reducer有两个作用:初始化状态,加工状态
3).reducer被第一次调用时,是store自动触发的,传递的preState是undefined,传递的action是:{type:‘@@REDUX/INIT’}
5️⃣ 在index.js中监测store中的状态的改变,一旦发生改变重新渲染
备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。
redux完整版本写法
在精简版中,action对象是我们自己手动传入的,接下来实现redux自动帮我们创建action对象。
在redux文件夹下创建count_action.js文件,该文件专门为Count组件生成action动作对象。
redux=> count_action.js:
// 分别暴露
export const createIncrementAction = (data) => {
return {
type: 'increment', data: data }
}
export const createIDecrementAction = (data) => {
return {
type: 'Decrement', data: data }
}
在Count组件引入count_action.js文件里分别暴露的函数:
// 引入actionCreator,专门用于创建action对象
import {
createIncrementAction, createDecrementAction } from '../../redux/count_action'
调用函数,自动生成action对象:
// 加法
increment = () => {
// 获取用户输入
const {
value } = this.selectNumber
store.dispatch(createIncrementAction(value * 1))
}
以此类推,将所有方法内手动创建的action对象更改为使用函数自动生成的action对象。
Count组件=> index.jsx:
import React, {
Component } from 'react'
// 引入store,用于获取redux中保存的状态
import store from '../../redux/store'
// 引入actionCreator,专门用于创建action对象
import {
createIncrementAction, createDecrementAction } from '../../redux/count_action'
export default class Count extends Component {
componentDidMount() {
// 检测redux中状态的变化,只要变化,就调用render
store.subscribe(() => {
// 只要reudx里保存的任何一个状态发生改变,就调用该回调
// console.log('@')
this.setState({
})
})
}
// 加法
increment = () => {
// 获取用户输入
const {
value } = this.selectNumber
store.dispatch(createIncrementAction(value * 1))
}
// 减法
decrement = () => {
// 获取用户输入
const {
value } = this.selectNumber
store.dispatch(createDecrementAction(value * 1))
}
// 奇数再加
incrementIfOdd = () => {
// 获取用户输入
const {
value } = this.selectNumber
// 读取原来的状态值
const count = store.getState()
if (count % 2 !== 0) {
store.dispatch(createIncrementAction(value * 1))
}
}
// 异步加
incrementAsync = () => {
// 获取用户输入
const {
value } = this.selectNumber
setTimeout(() => {
store.dispatch(createIncrementAction(value * 1))
}, 500)
}
render() {
return (
<div>
<h1>当前求和为:{
store.getState()}</h1>
<select ref={
c => this.selectNumber = c}>
<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.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={
this.incrementAsync}>异步加</button>
</div>
)
}
}
我们还可以创建一个constant.js文件,用于定义action对象中type类型的常量值,原来书写的type类型是字符串,不利于维护,万一拼错了,没有提示,所以目的只有一个:便于管理的同时防止程序员单词写错。
redux=> constant.js:
//分别暴露
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
redux=> count_action.js:
import {
INCREMENT, DECREMENT } from './constant'
// 分别暴露
export const createIncrementAction = (data) => {
return {
type: INCREMENT, data: data }
}
export const createDecrementAction = (data) => {
return {
type: DECREMENT, data: data }
}
redux=> count_reducer.js:
import {
INCREMENT, DECREMENT } from './constant'
// 初始化state
const initState = 0
// preState = initState :es6语法,给形参prevState赋初始值
export default function countReducer(preState = initState, action) {
console.log(preState, action)
// 从action对象中获取:type,data
const {
type, data } = action
// 根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //如果是减
return preState - data
default:
return preState
}
}
总结求和案例_redux完整版:
新增文件:
1️⃣ count_action.js 专门用于创建action对象
2️⃣ constant.js 放置由于编码疏忽写错的action中的type值
redux异步action版
action不仅是Object类型的一般对象(同步action),还是一个function函数值(异步action)。
在上述的案例中,我们实现异步加按钮这个操作时,我们是在Count组件里直接写了一个定时器,5s后自动实现加运算,action是Object类型的一般对象,这是同步action版。(好比客人去餐厅吃饭,客人(React component)等5s后,叫服务员(action creator)点餐)
// 异步加
incrementAsync = () => {
// 获取用户输入
const {
value } = this.selectNumber
setTimeout(() => {
store.dispatch(createIncrementAction(value * 1, 500))
}, 500)
}
// 同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = (data) => {
return {
type: INCREMENT, data: data }
}
但是,我不想在组件里用定时器,直接在函数里,传一个5s的参数,告诉action等5s后进行加运算,这里的action是一个function函数值,这是异步action版。(好比客人去餐厅吃饭,客人(React component)告诉服务员(action creator)5s后点餐)
// 异步加
incrementAsync = () => {
// 获取用户输入
const {
value } = this.selectNumber
// setTimeout(() => {
store.dispatch(createIncrementAsyncAction(value * 1, 500))
// }, 500)
}
在组件里写好了createIncrementAsyncAction()函数,但还没定义该函数,所以要在count_action.js文件里定义该函数。
import store from './store'
// 异步action,就是指action的值为函数,异步action中一般都会调用同步action
export const createIncrementAsyncAction = (data, time) => {
return () => {
setTimeout(() => {
store.dispatch(createIncrementAction(data))
}, time)
}
}
但是,这里交给store的是一个function函数类型的值,store不能处理函数类型的值,会报错,需要使用一个中间件,让store执行这个函数里的异步任务。
安装中间件redux-thunk:
npm add redux-thunk
在store.js文件里引入中间件redux-thunk:
// 引入redux-thunk,用于支持异步任务
import thunk from 'redux-thunk'
还要引入一个执行中间件的applyMiddleware:
import {
applyMiddleware } from 'redux';
//在哪执行
export default createStore(countReducer, applyMiddleware(thunk))
在createStore时,将applyMiddleware传入作为第二个参数,applyMiddleware本身是一个函数,执行中间件,所以要传入thunk。
总结求和案例_redux异步action版:
1️⃣ 明确:延迟的动作不想交给组件自身,想交给action
2️⃣ 何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
3️⃣ 具体编码:
- npm add redux-thunk,并配置在store中
- 创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务
- 异步任务有结果后,分发一个同步的action去真正操作数据
4️⃣ 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步任务action
今天的分享就到这里啦 \textcolor{red}{今天的分享就到这里啦} 今天的分享就到这里啦
原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!
边栏推荐
- [shutter -- layout] flexible layout (flex and expanded)
- 移动语义和完美转发浅析
- MySQL数据库【数据库基础--引入篇】
- R语言使用quantile函数计算向量数据或者dataframe指定数据列的分位数(百分位数)
- 基于自学习的机器人决策系统(达闼科技赵开勇)
- 四旋翼飞行器1——结构和控制原理
- 吃透Chisel语言.21.Chisel时序电路(一)——Chisel寄存器(Register)详解
- Mee | Zhejiang University Chenglei group develops a new method for designing and constructing synthetic flora
- 树莓派ssh登录
- PowerCLi 管理VMware vCenter 一键批量部署OVF
猜你喜欢

数据链路层 -------- 以太网 和 ARP

Little fish sends lidar | just dinner is the first lottery

elk筆記25--快速體驗APM

PowerCLi 管理VMware vCenter 批量部署导出导入
![[shutter -- layout] linear layout (row and column)](/img/0e/df0f4bce73dd9785cc843adaf371d0.png)
[shutter -- layout] linear layout (row and column)

Weights & Biases (一)

UPC 2022 summer personal training game 12 (number of combinations b)

H7-TOOL的CANFD/CAN接口脱机烧写操作说明, 已经更新(2022-07-12)

树莓派ssh登录

基于自学习的机器人决策系统(达闼科技赵开勇)
随机推荐
socat 使用「建议收藏」
ACM MM 2022 Oral | DIG: 自监督文字识别的新框架,刷新11个公开场景文字数据集的识别性能,平均提升5%...
When does MySQL use table locks and row locks?
Boundschecker usage "recommended collection"
Technical scheme of face recognition system
单调队列优化DP
Type-C蓝牙音箱单C口可充电可OTG方案
.Net CLR R2R编译的原理简析
R语言筛选dataframe指定的数据列、R语言排除(删除)dataframe中的指定数据列(变量)
搜索二维矩阵
Analyse de l'industrie | interphone logistique
看完这篇,彻底搞懂 gRPC!
将本地镜像发布到阿里云仓库
[machine learning] Wu Enda: lifelong learning
SecureCRT乱码问题解决方法[通俗易懂]
elk筆記25--快速體驗APM
R语言data.table包进行数据分组聚合统计变换(Aggregating transforms)、计算dataframe数据的分组最小值(min)
Summarize some recent tricks
Alibaba's latest masterpiece! It took 187 days for the liver to come out. 1015 pages of distributed full stack manuals are so delicious
简历上写的电商,那请问Redis 如何实现库存扣减操作和防止被超卖?