🌈个人主页:前端青山
🔥系列专栏:React篇
🔖人终将被年少不可得之物困其一生
依旧青山,本期给大家带来React篇专栏内容:React-Redux(一)
目录
1、简介
2、三大原则(重点)
3、redux的基本使用
1、简介
2013年Facebook提出了Flux架构的思想,引发了很多的实现。2015年,Redux出现,将Flux与函数式编程结合一起,很短时间内就成为了最热门的前端架构。
简单说,如果你的UI层非常简单,没有很多互动,Redux就是不必要的,用了反而增加复杂性。
如果你的项目的迭代变得越来越复杂,组件的数量和层级也变得越来越多,越来越深,此时组件间的数据通信就变得异常的复杂和低效,为了解决这个问题,引入了状态管理(redux)从而很好的解决多组件之间的通信问题。
如果需要使用Redux请先进行安装:
网址:Getting Started with Redux | Redux
npm i -S redux
作用:项目进行大规模数据管理的工具。
提醒:所有的代码需要从0开始写(不像vuex,选择了vuex后会自带一些代码)
2、三大原则(重点)
-
单一数据源
-
整个应用的
state
(这个state不是组件中的state,请不要混淆)被储存在一棵对象结构树中,并且这个对象结构只存在于唯一一个store中
-
-
State是只读(相对,相对旧数据)的
-
唯一改变state的方法就是触发dispatch+action,action是一个用于描述已发生事件的普通对象(action普通对象必须要有
type
属性,值是什么无所谓,其余属性也无所谓)。
-
-
(最终修改数据的方法)使用纯函数(一个函数的返回结果只受到其形参的影响,则其就是纯函数)来执行修改
-
为了描述action如何改变state tree ,我们需要编写reducer【看作是vuex中的mutations里的方法】,==reducer必须是纯函数==,它接收先前的state和action,并返回新的state(不会合并的,自行注意这个坑)
-
纯函数是函数式编程的概念,必须遵守以下一些约束。
不得改写参数
不能调用系统 I/O 的API
不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果
请注意:由于reducer被要求是纯函数,所以reducer函数里面不能改变State,必须返回一个全新的数据(不会自动合并原始数据的,因此一定要注意:别把原始数据搞丢了)。
操作原理图
a. store通过reducer创建了初始状态
b. view通过store.getState()获取到了store中保存的state挂载在了自己的状态上
c. 用户产生了操作(事件),调用了actions 的方法
d. actions的方法被调用,创建了带有标示性信息的action(描述对象,描述如何修改数据)
e. actions将action通过调用store.dispatch方法发送到了reducer中
f. reducer接收到action并根据标识信息判断之后返回了新的state(自己注意合并的问题)
g. store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state
-
store.getState():用于获取仓库中初始的数据(一次性)
-
store.dispatch():用于派发修改数据的任务,参数是action普通对象
-
store.subscribe(callback):视图组件用于订阅新数据的方法(二次及以后的数据更新,使之产生类似于vue的响应式store数据)
3、redux的基本使用
案例:在组件中展示一个按钮,点按钮后给redux中的数字+9,数字初始为0。实现一个计数器的效果
步骤:
-
创建store
-
创建视图组件(展示store中的数据)
-
修改
-
回显数据到视图组件
实现步骤
a. 创建默认数据源:
// 1. 这是仓库store
// a. 导入需要使用的成员
// createStore方法,作用用于产生仓库
import { createStore } from "redux";
// b. 创建数据源
// 默认数据源是一个普通对象,可以有很多的数据
const defaultState = {// 定义初始化的数据count: 0,
};
// c. 创建纯函数reducer(方法名叫什么无所谓)
// 作用:负责返回state(可能是直接返回state,也可能是返回修改后的state)
// 语法:reducer(state = defaultState,actions)
function reducer(state = defaultState, actions) {// 在返回之前写修改数据源的操作return state;
}
// d. 产生仓库
// 产生仓库的时候需要往仓库中存放数据源,因此需要传递reducer过去
const store = createStore(reducer);
// e. 导出仓库
export default store;
为了方便调试redux(可选安装),建议去谷歌商店安装redux dev tools
,在使用的时候需要参考其说明页面
redux工具条在安装好之后不能直接使用,需要配置仓库代码,然后才能使用。
// d. 产生仓库
// 产生仓库的时候需要往仓库中存放数据源,因此需要传递reducer过去
const store = createStore(reducer,// 必须要加上一段插件的配置工具,才能在浏览器中使用redux扩展window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
显示效果:
b. 建立视图组件并且展示数据源
import React, { Component } from "react";
// 需要导入store
import store from "../store/index";
class Counter extends Component {// 在constructor中获取store中的数据constructor(props) {super(props);// 获取store数据(一次性,不具备响应式)this.state = store.getState();// 订阅数据的更新store.subscribe(() => this.setState(() => store.getState()));}render() {console.log(this.state);return (<div><div>当前Store中的数据是:{this.state.reducer.count}</div><button onClick={this.addCount.bind(this)}>点击+9</button><hr /><div>当前Store中的数据是:{this.state.reducer2.age}</div><button onClick={this.addAge.bind(this)}>点击+1</button></div>);}
// 点击+9addCount() {// 描述数据如何更改的对象,其必须有type属性let action = { type: "mod_count", payload: 9 };// 通过store.dispatch去派发action(会将该action派发给所有的reducer,每个reducer都会被执行,因此一定要注意type的取值)store.dispatch(action);}
// 点击+1addAge() {let action = { type: "mod_age", payload: 1 };store.dispatch(action);}
}
export default Counter;
c. 修改操作
视图组件中的代码:
handler() {// 3. +9这个修改操作需要通过普通对象去描述(actions)const action = {// type是用于在reducer方法中做条件判断用的type: "add",// 另一个属性用于声明本次修改具体的值是多少payload: 9,};// 派发修改任务store.dispatch(action);
}
仓库文件的代码:
function reducer(state = defaultState, actions) {console.log(actions);//判断是否是加法操作if (actions.type === "add") {return { count: state.count + actions.payload };}// 在返回之前写修改数据源的操作return state;
}
d. 回显新的数据
// 构造函数
constructor(props) {super(props);// 2. 在视图组件中获取初始的仓库数据// getState()方法是store对象内置的方法this.state = store.getState();// 4. 订阅新的数据store.subscribe(() => {// 获取新数据修改当前的statethis.setState(() => store.getState());});
}
如果有多个reducer,需要通过combineReducers
方法进行合并,代码如下:
// 合并reducer
// 有点类似于vuex的命名空间
const reducers = combineReducers({ reducer, reducer2 });
// c. 创建store对象(通过createStore方法),目前(后续有变)其参数就是reducer
const store = createStore(reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());