搬砖搬砖,分享点搬砖技巧。
第六章了,差不多结束了 ,还有些零零散散的,慢慢搬吧。
之前的章节内容可点这~
第六章 — redux
6.1 什么是 redux
官方是这样子说的 :redux
是 JavaScript 应用程序的可预测状态容器 ,它可以帮助您编写行为一致、在不同环境(客户端、服务器和本机)中运行且易于测试的应用程序。
官方的解释有时候总是看不懂的
说一下我的理解。
JavaScript 应用程序 : redux 和 react 可是两回事,只是长的像而已。 redux 可以在任何应用程序使用。
redux 有一个核心的东西 ,就是 store . 那现在有了一个新的问题,什么是 store 。
store
英文的释义是商店。在 redux 里它是一个存储数据的地方,就相当于一个容器,一个仓库。整个程序只有一个 store 。这便于状态的集中管理。
为什么说是可预测呢?
因为 redux 管理的数据的修改过程是我们设置的,也就是我们已经告诉他应该怎么做。并且每次修改之前是会接收到之前的状态。过程是可预测,可跟踪的。
6.2 为什么需要 redux
当程序的功能比较复杂,组件较多,并且需要共享状态且共享状态困难时, 使用redux 是一个较好的解决方案。
我们可以通过这两张图理解:有 A , B ,C ,D, 四个房子(组件) ,它们总是会相互借东西。相互交流。(组件交互,状态共享,修改数据)。那么以我们之前的方法,像通过共同的父组件来传递数据,那么父组件会变得很臃肿,因为需要定义一些它本身不需要的状态和方法,只是为了方便儿子们交流。
或者使用消息订阅-发布机制。 B 需要 A的某个数据,就需要订阅,然后 A 发布 。然后 D也需要,于是 D 也需要订阅。个组件来来往往就像如图一样乱七八糟。
而使用 redux . 就相当于建了一个仓库 , 各房子把需要共享的东西放在仓库,谁需要谁去拿。那么不但把数据需要共享的资源统一一个地方存储,并且方便了其他组件去使用。
非必要,不使用 redux
并不是如何程序或者 使用了 react 就需要使用 redux 的 。
有句话这样子说
“如果你不知道是否需要 Redux,那就是不需要它。”
为什么呢 , redux 是便于组件共享状态的,如果组件组件交互少,需要共享的状态不多,且不需要 redux 便能解决的那么根本就不需要使用 redux 。
使用场景
- 组件间需要共享状态,交互较多
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- View要从多个来源获取数据
6.3redux 的工作流程图解
在介绍如何使用之前,先了解一下redux 的工作流程是很有必要的,这有助于理解。
Component 便是组件了
ActionCreators redux 分为 3个部分,核心部分是 Store , 然后是 ActionCreators 和 Reducers.
其中ActionCreators 是创建 action 的 。也就是创建行为的一个模块。
Reducers 处理 dispatch 发出的行为 。也就是实际做出行动的模块。
Store 便是保存状态的核心部分 无论是发出行为,存储数据,还是把结果反应出去都是通过它。
我们可以理解为 redux 就是一个饭店 ,各组件是客人,客人通过 服务员 ( ActionCreators) 下单 ,告诉需要什么菜。于是服务员跟老板说了(Store) , 然后老板让厨师(Reducers) 做菜。最后客人从老板这儿了拿菜。这当然与实际有些不同,但这不妨碍我们更好理解这个过程。
回到实际, 组件在需要发出行为时,调用了 store上的 dispatch 方法 ,途中向 ActionCreators 拿了一下 action。并作为 dispatch 的参数传给 store 。 也就是实际上调用 dispatch方法 的是 组件。
然后Store 把 当前的状态的 action 传给 reducer 。 reducer 处理完后返回新的 状态 给 store。组件再通过 store 的 getState() 方法拿到新的状态数据。
6.4 redux 的使用
安装及基础准备
通过 npm
npm install redux
通过 yarn
yarn add redux
创建相关文件夹和文件
创建组件和 redux 文件夹及 redux 内相关文件(如图所示)
因为 不同组件有不同的行为,因此可以把不同的 创建action 的文件放在一个文件夹里。如图中的 actions文件夹。
同理 不同组件发出行为的操作也不同 ,也需要不同的 reducer , 因此放在同一个文件夹下。
而 store 仅有一个,因此直接放于 redux文件夹下即可。
constant.js 文件, 用于存储 type 常量,因为 type 的值是我们事先给定的,通过不同 type 触发不同的操作。因此在组件和 reducer 里都需要使用到 type 的值。使用常量,是便于修改,放在打错字。
基本使用
假设我们需要完成一个例子
将结果的数据存放在 state 中 , 点击 + 或 - 可以对数据进行加一或者减一。结果默认显示 99 。
action
创建 action 的文件不需要引入什么 API ,我们需要创建相关方法,该方法返回通过 action
。
action
是一个对象, 包括两个属性 type
和 data
, 分别是类型和数据, type 会表明到时候 reducer 应该执行的操作, data 是传递的数据。此数据来源组件。也就是 action 文件暴露的方法是给组件调用的,并且组件会传入一个数据。
// 分别暴露 创建的相应的创建 action 的方法 ,当其他地方需要使用action时,调用这个方法便创建并可以返回 action。
export let createIncrease = (data) => ({ type: “increase”, data })
export let createDecrease = (data) => ({ type: ”decrease“, data })
reducer
reducer文件 也是不需要引入什么 API 的。它用来创建为某组件专门服务的 reducer 函数。仅一个,判断 type 提供不同的操作。
reducer 函数接收两个参数 , 第一个是 preState , 其实是当前的状态(因为经过此次操作后,会返回新的 State ,因此把它叫做 preState, 含义是之前的状态),第二个参数是 action 。
reducer 会在 redux 加载后执行一次,此次会返回一个默认值。
/*
1. 此文件用来创建一个为 Count 组件的 服务的 reducer . 本质是一个函数
2. 函数接收两个参数 , 第一个是之前的 preState , 第二个是动作对象 action (包括行为,和数据)
*/
export default function countReducer(preState, action) {
console.log(preState);
console.log(action);
const {
type, data } = action
switch (type) {
case "increase":
return preState + data
case "decrease":
return preState - data
default:
return 99 // 初始返回的默认值
}
}
注意:
- preState 如果是原始值可以修改本身,再返回本身,如果是引用值切记不能修改本身然后返回本身 因为 redux 会对返回值与 preState 进行地址比较,如果是一样的地址会导致更新的失败。
// 如果是原始值,如此操作不影响结果
case "increase" :
preState += data
return preState
// 如果是引用值 ,以下操作是错误的
case "pop" :{
preState.pop()
return preState
}
- reducer 要求必须是一个纯函数。但如果不存并不会报错。存函数需要满足以下几点操作