文章目录

  • Redux的使用过程
    • Redux测试项目的搭建
    • Redux的基本使用步骤
    • Redux目录的结构划分
    • React的三大原则

Redux的使用过程

Redux测试项目的搭建

1.创建一个新的项目文件夹:learn-redux

# 执行初始化操作 npm init -yyarn init -y

# 安装redux:npm install redux --saveyarn add redux

2.创建src目录,在src目录下创建一个store文件夹, 并且在该文件夹下创建index.js文件

3.可以修改package.json用于执行index.js, 也可以不配置, 直接使用node命令运行

"scripts": {"start": "node src/index.js"
}

Redux的基本使用步骤

1.创建一个对象,作为我们要保存的状态state:

// 由于测试项目在node环境下, 因此使用require方式导入
const { createStore } = require("redux")// 创建的要存储的state: initialState
const initialState = {name: "chenyq",age: 18
}

2.创建Store来存储这个state

由于创建的state是不能直接放到创建的store中的, 需要通过reducer将数据添加到store中, 因此创建store时必须创建reducer;

reducer函数的返回值, 会作为store之后存储的state

// 定义reducer, 将要存储的state作为返回值返回
function reducer() {return initialState
}// 创建的store, 内部会自动回调reducer, 拿到initialState
const store = createStore(reducer)// 导出store
module.exports = store

我们可以在其他文件中通过 store.getState 来获取当前的state;

// 导入创建的store
const store = require("./store")// 获取store中的state
console.log(store.getState())

3.通过action来修改state

错误演示: 直接修改store

store.getState().name = "abc"

修改store中的数据不能直接修改, 必须要通过dispatch来派发action;

通常action中都会有type属性,也可以携带其他的数据;

// 定义一个action
const nameAction = { type: "change_name", name: "abc" }
// 派发action
store.dispatch(nameAction)

当然上面代码中, 也可以写为一行

// 派发action
store.dispatch({ type: "change_name", name: "abc" })

4.修改reducer中的处理代码

reducer接收两个参数:

参数一: store中当前保存的state

参数二: 本次需要更新的action

只要调用dispatch就会重新执行reducer函数

这里一定要记住,reducer是一个纯函数,不可以直接修改state, 后面我会讲到直接修改state带来的问题;

// 第一次state是undefined, 因此给一个默认值将初始化数据添加到store中
function reducer(state = initialState, action) {// 有数据更新时, 返回一个新的stateif (action.type === "change_name") {return { ...state, name: action.name }}// 没有数据更新时, 返回之前的statereturn state
}

5.可以在派发action之前,监听store的变化:

通过store.subscribe()函数可以监听store中的数据变化

store.subscribe()函数的参数接收一个函数, 该函数在store数据发生更新自动回调

const store = require("./store")// 例如: 监听数据的变化, 当store变化, 就获取最新的state
store.subscribe(() => {console.log(store.getState())
})store.dispatch({ type: "change_name", name: "abc" })
store.dispatch({ type: "change_name", name: "aaa" })

6.封装函数动态生成action

例如上面代码中, 我们修改名称多次, 只有传入的action的name属性值不相同, 那么我们可以封装一个函数, 动态的生成action, 这也是开发中一贯的做法

// 创建修改name的action
const changeNameAction = (name) => ({type: "change_name",name
})
// 创建修改age的action
const changeAgeAction = (num) => ({type: "change_age",num
})// 在派发action时, 我们就可以调用函数即可获取action
store.dispatch(changeNameAction("aaa"))
store.dispatch(changeNameAction("bbb"))
store.dispatch(changeNameAction("ccc"))store.dispatch(changeAgeAction(10))
store.dispatch(changeAgeAction(20))
store.dispatch(changeAgeAction(30))
store.dispatch(changeAgeAction(40))

Redux目录的结构划分

如果我们将所有的逻辑代码写到一起,那么当redux变得复杂时代码就难以维护

例如上面代码中, 我们封装的动态创建action的函数, 这种动态生成action的函数在项目中可能会有很多个, 而且在其他多个文件中也可能会使用, 所以我们最好是有一个单独的文件夹存放这些动态获取action的函数

接下来,我会对代码进行拆分,将store、reducer、action、constants拆分成一个个文件。

创建store/index.js文件: index文件中, 我们只需要创建store即可

const { createStore } = require("redux")
// 引入reducer
const reducer = require("./reducer")// 创建的store, 内部会自动回调reducer, 拿到initialState
const store = createStore(reducer)// 导出store
module.exports = store

创建store/reducer.js文件: 在真实项目中, reducer这个函数我们会越写越复杂, 造成我们index.js文件越来越大, 所以我们将reducer也抽离到一个单独的文件中

const { CHANGE_NAME, CHANGE_AGE } = require("./constants")// 创建的要存储的初始化state
const initialState = {name: "chenyq",age: 18
}// 定义reducer, 将要存储的state作为返回值返回
// 第一次state是undefined, 因此给一个默认值将初始化数据添加到store中
function reducer(state = initialState, action) {switch(action.type) {case CHANGE_NAME: return { ...state, name: action.name }case CHANGE_AGE: return {...state, age: state.age + action.num}}// 没有数据更新时, 返回之前的statereturn state
}module.exports = reducer

创建store/constants.js文件: 将type的类型定义为常量(防止写错的情况), 这些常量最好也防止一个单独的文件中

// store/constants.jsconst CHANGE_NAME = "change_name"
const CHANGE_AGE = "change_age"module.exports = {CHANGE_NAME,CHANGE_AGE
}

创建store/actionCreators.js文件: 将封装的动态创建action的函数放在该文件中, 在需要使用的地方导入即可

const { CHANGE_NAME, CHANGE_AGE } = require("./store/constants")// 创建修改name的action
const changeNameAction = (name) => ({type: CHANGE_NAME,name
})
// 创建修改age的action
const changeAgeAction = (num) => ({type: CHANGE_AGE,num
})module.exports = {changeNameAction,changeAgeAction
}

最终形成如下目录结构, 这也是官方推荐的目录结构, 一个store中包含这四个文件夹

注意:node中对ES6模块化的支持, 建议使用CommonJS规范


React的三大原则

单一数据源

整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中:

Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护;

单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;

State是只读的

唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State:

这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state;

这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;

使用纯函数来执行修改

通过reducer将旧state和actions联系在一起,并且返回一个新的State:

随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;

但是所有的reducer都应该是纯函数,不能产生任何的副作用;

Redux的基本使用过程详解相关推荐

  1. hadoop作业初始化过程详解(源码分析第三篇)

    (一)概述 我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程.在作业到达JobTracker之后初始化之前,JobTracker会通过submit ...

  2. Hadoop学习之Mapreduce执行过程详解

    一.MapReduce执行过程 MapReduce运行时,首先通过Map读取HDFS中的数据,然后经过拆分,将每个文件中的每行数据分拆成键值对,最后输出作为Reduce的输入,大体执行流程如下图所示: ...

  3. python的执行过程_在交互式环境中执行Python程序过程详解

    前言 相信接触过Python的伙伴们都知道运行Python脚本程序的方式有多种,目前主要的方式有:交互式环境运行.命令行窗口运行.开发工具上运行等,其中在不同的操作平台上还互不相同.今天,小编讲些Py ...

  4. 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  5. JetBrains DataGrip工具配置数据库过程详解

    JetBrains DataGrip工具配置数据库过程详解 DataGrip是一款数据库管理客户端工具,方便连接到数据库服务器,执行sql.创建表.创建索引以及导出数据等. DataGrip 是 Je ...

  6. Apache+PHP配置过程详解

    Apache+PHP配置过程详解 经过两晚上的奋斗终于将Apache配置PHP成功,安装配置过程中走了不少弯路,特记录之. 1.Apache配置PHP个人认为首先要注意的是Apache和PHP的版本信 ...

  7. Mysql加锁过程详解(3)-关于mysql 幻读理解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  8. 理论经典:TCP协议的3次握手与4次挥手过程详解

    理论经典:TCP协议的3次握手与4次挥手过程详解 https://blog.csdn.net/omnispace/article/details/52701752 转载于:https://www.cn ...

  9. python画动图-Python绘制动态水球图过程详解

    先来看看绘制的动态水球图: 没有安装PyEcharts的,先安装PyEcharts: # 安装pyecharts模块,直接安装就是最新的版本pip install pyecharts 安装好PyEch ...

最新文章

  1. 机器学习算法1_线性回归
  2. VMware vSphere4.1看图识HA
  3. Express中post请求req.body为空
  4. 【01】《正则表达式必知必会》(已看)(仅存放)
  5. oracle修改某个数据类型,Oracle 修改某个字段的数据类型三种方式
  6. 得到进程id_搞懂进程组、会话、控制终端关系,才能明白守护进程干嘛的?
  7. c语言程序基本设计,C语言程序的设计基本6.ppt
  8. vuedraggable能实现自由拖拽功能吗?_基于 vue.js 仿禅道主页拖拽效果
  9. P1350 车的放置
  10. 4款基于Django框架的开源软件推荐
  11. c语言限流算法,分布式限流常用算法
  12. 最大后验估计与共轭分布
  13. 633.平方数之和(力扣leetcode) 博主可答疑该问题
  14. 稳压二极管型号对应电压表
  15. 【入门】QQ聊天机器人--HelloWorld篇
  16. 【每日学习】深度学习相关知识
  17. Android开发示例
  18. springboot电子邀请函制作
  19. 复数与三角函数的转换
  20. 在最熟知的芯片,解析最不为人知的秘密--Nordic的蓝牙芯片nRF52832。

热门文章

  1. java数据结构停车场管理问题_数据结构——停车场问题
  2. NOIP2017 酱油记
  3. linux下VIM永久显示行号
  4. 爬虫平台的架构实现和框架的选型(二)
  5. 2018.10.1(这不仅是一篇日记,也是mac使用心得整理,未完待续……)
  6. 记录:实现钉钉(企业内部应用)登录第三方网站
  7. 每日新闻简报 365资讯简报12条
  8. validationEngine参数详解
  9. [GN] 谷歌元构建系统GN,toolchain配置
  10. 有关列表折叠展开的问题