首先我们要先知道什么是状态管理器,这玩意是干啥的?

当我们在多个页面中使用到了相同的属性时就可以用到状态管理器,将这些状态存到外部的一个单独的文件中,不管在什么时候想使用都可以很方便的获取。

react和vue有些不同,react没有自己专属的状态管理方式。它使用的其实是js相关的状态管理器。我们需要记住的是,视图可以引起状态的改变,而状态的改变会导致视图的二次渲染。

说了这么半天,那么我们在react中到底是怎样使用状态管理器的呢?

redux闪亮登场

redux的前身技术是flux,他和flux很相像,但是又不完全相同。两者都规定将模型的更新逻辑全部集中在一个层面中(Flux之中的store,redux之中的reducer);但是redux中没有dispatcher的概念,他依赖的是纯函数来做事件处理器;并且redux不回去修改你的数据,它会返回一个新的对象用于更新state状态。

首先我们先来认识一下redux中的一些属性

1、store:

保存数据/状态的地方,可以把它看成是一个容器。记得在整个应用之中只能有一个store

import { createStore } from 'redux'
const store = createStore(fn)

  2、state:

可以把state看成是store的实例对象,他包含了状态管理器中所有的状态,是某个时间点所有数据/状态的集合

const state = store.getState()

  3、action

redux中最重要的属性之一,唯一修改store种状态的方式就是提交一个action;action是一个对象,具有type属性,通常这个type属性作为提交的关键key值

const action = {
type: 'ADD_TODO',
payload: 'Learc Redux' //这里的payload是作为参数传入的,可以不写
}

  4、store.dispatch():

提交action的唯一方式,我们就是通过这种方式将action提交到状态管理器,不管后期使用了什么其他的状态管理其工具,最终都归结与这里。

store.dispatch({
type: 'ADD_TODO'
})

  5、reducer:

store在收到action之后,必须返回一个新的state,这样view才会发生变化,而这个state的计算过程就叫做reducer

reducer是一个函数,他接受当前的state和action,返回一个全新的state

const reducer = (state = {
count: 10 //给state中的属性设置初始值,因为状态管理器在每次刷新后都会清空,我们可以从本地获取上次存储的值作为初始值
}, action) => {
switch (action.type) {
case 'REDUCE':
// 这里可以看到我们根据action的type值作为key值进行查找,当dispatch的时候,就可以根据这些key值的判断查找到要执行的操作
return { ...state, count: state.count - action.payload }
//我们根据action的需要,在原有的state基础上,返回了一个新的state对象,没有修改原来的state
case 'ADD':
return { ...state, count: state.count + action.payload } default:
return state;
}
} export default reducer

  可以看到我们返回新的state对象的方式是通过ES6中的 ... 语法,这种方式看起来是不是有点复杂,有点点low?那么我们介绍一种新的方式,首先引入immutable组件

yarn add immutable -S

  这种方式其实是js实现了一种深拷贝,将原来的state对象深拷贝了一份,这样对新的state对象做出任何修改都不会影响到原来的state,是不是特别香!!!

使用方式:

import { Map } from 'immutable'        //引入Map函数

const user = (state = Map({        //使用Map深拷贝了state
isLogin: localStorage.getItem('isLogin') === 'true',
token: localStorage.getItem('token') || '',
adminname: localStorage.getItem('adminname') || '',
role: localStorage.getItem('role') * 1 || 1
}), action) => {
switch (action.type) {
case 'CHANGE_LOGIN_STATE':
return state.set('isLogin', action.payload) //set方式写入
case 'CHANGE_TOKEN':
return state.set('token', action.payload)
case 'CHANGE_ADMIN_NAME':
return state.set('adminname', action.payload)
case 'CHANGE_ROLE':
return state.set('role', action.payload)
default:
return state
}
} export default user
state => {
return {
adminname: state.getIn(['user', 'adminname']), // get方式获取值, 参数是这种形式
//第一个参数的含义: user状态管理器中的
//第二个参数含义: 名为adminname的状态/属性
}
}

6、设计状态管理器

首先根据模块化开发的思想,我们可以在一个项目中设计多个种类状态管理器,最后合并到一个里面;例如,商品的状态,用户信息的状态....

import { createStore, combineReducers } from "redux";
// 这个combineReducers方法就是模块化开发的关键,它帮助我们把所有分模块的状态管理器合并到一起
import pro from './modules/pro'
import app from './modules/app' const reducer = combineReducers({ //把分模块创建的所有reducer都集中到这里的reducer
pro, app
}) const store = createStore(reducer) export default store

  帮助解读阶段

我们要知道一件事,当我们在某一个时间点希望获取状态或者修改状态的时候,状态管理器store会为我们生成一个state实例对象,我们可以对这个实例对象进行操作。state的变化会引起View视图的改变,但是因为用户们接触不到state,只能接触到View,所以state的变化必然也必须是由View引起的!!!而action其实就是view 发出的一个通知,当用户修改了view的时候,就会发出这个通知,告诉程序,state需要发生改变了。

//我们可以这样理解,dispatch,action,store三者的关系可以看成是邮局,邮件,收信人
//我们想寄一封信(action),告诉朋友(收信人),我们找到工作了,需要通过邮局(dispatch)的帮助;当邮局帮我们把邮件送到了收件人的地方时,收件人就获取到了我要传递的信息,也会做出响应的改变
//我们在调用dispatch的时候,通过type(key值)找到对应的邮件送到store

  状态管理器是如何使用的呢?

// 可以通过provider和connect在组件中对状态管理器进行‘链接’,链接成功之后就可以使用状态管理器中的状态和方法了

// /src/xxx/index.jsx
import {connect} from 'react-redux' function App (props) {
...
}
export default connet(mapStateToProps, mapDispatchToProps)(App) // /index.js
import {Provider} from 'react-redux'
import App from './App.jsx'
import store './store/index.js' ReactDom.render (
<React.StrictMode>
<Provider store = { store }>
<App />
</Provider>
</React.StrickMode>
) //也可以使用到装饰器的高阶函数 @connect @withRouter //以往从状态树取出对应的数据,让后通过props传给组件使用通过react-redux自带的connect()方法
class Home extends React.Component {
//....
}
export default connect(state => ({todos: state.todos}))(Home); //使用装饰器的话就变成这样,好像没那么复杂
@connect(state => ({ todos: state.todos }))
class Home extends React.Component {
//....
}

  这里我们对这种方式做出讲解:

我们要链接状态管理器,首先在整个项目的入口文件index.js中引入状态store,通过Provider的方式将store作为参数传递给子组件,有点类似于祖先组件给后代组件传值的方式

其次,我们要在使用状态管理器的组件中通过connect这一个高阶函数进行连接,该高阶函数的原理是,传入函数作为参数,返回另一个函数

mapStateToProps:

从名字可以看出,是把state中的状态遍历处理,放到props中,我们就可以在函数式组件中的props参数值里面获取到state.

mapDispatchToProps:

将状态管理器中的提交方法存入到props中,这样我们就可以在组件中对状态管理器中的状态进行修改。

const App = (props) => {
// 组件中直接就可以通过props访问到状态管理器中的状态
props.adminname
props.count
props.bannerList
props.reduceFn
...
}
export default connect(
// 可以看到这里就是传入两个函数,返回两个函数
state => {
return {
adminname: state.getIn(['user', 'adminname']), //这是一种存储状态的方式,一会会讲到
count: state.app.count, //参数是state,我们把app状态管理器中的count属性传递到props中的count
bannerList: state.pro.bannerList,
}
},
dispatch => {
return {
reduceFn () { //我们在这里定义了一个reduceFn,里面是dispatch的方法,我们在props中就可以通过reduceFn这个方法发送'REDUCE'提交的信息
dispatch({
type: 'REDUCE',
payload: 5 //payload为参数,可以不传
})
}
}
}
)(App)

  我们除了可以使用这种基本的方式修改状态意外,还可以使用一些工具

redux-thunk、redux-saga

redux-thunk的使用
//在store.js之中把thunk引入并挂载到状态管理器中

import { createStore, combineReducers, applyMiddleware} from 'redux'

import thunk from 'redux-thunk'
import app from './modules/app'
import pro from './modules/pro' const reducer = combineReducers({
app, pro
})
// 通过applyMiddleware将thunk挂载到状态管理器
const store = createStore(reducer, applyMiddleware(thunk)) export default store

  然后我们单独设计一个文件用来封装修改状态的方式,包含异步方式

// .../store/actionCreator/pro.js

// 这个文件就是专门用来触发异步操作
// thunk模块执行的时候, actionCreator 函数有默认的参数为dispatch
// 该dispatch 可以用来触发reducer
// 有时候在触发异步的时候, 需要传递参数,这个时候,可以在函数内部返回一个 actionCreator 函数
const actions = {
getBannerListAction (dispatch) {
fetch('http://121.89.205.189/api/banner/list')
.then(res => res.json())
.then(res => {
dispatch({
type: 'CHANGE_BANNER_LIST',
payload: res.data
})
})
},
getProListAction (count) { //有参数,返回一个函数,函数参数默认为dispatch
count = count || 1
return function (dispatch) {
fetch('http://121.89.205.189/api/pro/list?count=' + count)
.then(res => res.json())
.then(res => {
dispatch({
type: 'CHANGE_PRO_LIST',
payload: res.data
})
})
}
}
} export default actions

  可以把上面的步骤看成定义了一个action的对象,里面有一些提交action的dispatch,当我们要在组件中要修改状态时,可以直接在这个对象中使用函数,函数会自动发起请求,提交action。

在下面组件中的使用也可以看出来,我们dispatch(actions.getBannerListAction);其实就是提交aciton的形式,只不过我们把action修改和异步请求封装起来了

import actions from './store/actionCreator/pro'
const App = (props) => {
// props之中可以直接访问到
props.reduceFn()
props.addFn()
props.getBannerList()
props.getProList()
} const mapStateToProps = (state) => {
return {
count: state.app.count,
bannerList: state.pro.bannerList,
proList: state.pro.proList
}
} const mapDispatchToProps = (dispatch) => {
return {
reduceFn () { //通过正常方式修改状态
dispatch({
type: 'REDUCE',
payload: 5
})
},
addFn () {
dispatch({
type: 'ADD',
payload: 5
})
},
getBannerList () { //通过thunk方式修改状态
dispatch(actions.getBannerListAction)
},
getProList () {
dispatch(actions.getProListAction(2))
}
}
} export default connect(mapStateToProps, mapDispatchToProps)(App)

  链接的方式和普通的react-redux一模一样,最后也是通过dispatch一个action的方式修改状态

react-saga的使用

安装redux-saga

yarn add redux-saga  immutable redux-immutable -S

  

可以把redux-saga和redux-thunk看作是一种发送dispatch的方式,在旧时代我们送信(dispatch)是通过汽车、步行;使用工具可以看成是通过动车,飞机发送信件

  

import { createStore, combineReducers, applyMiddleware } from 'redux'

import createSagaMiddleware from 'redux-saga'

import mySaga from './mySaga' //异步操作说明

import home from './modules/home'
import app from './modules/app' const reducer = combineReducers({
app,
home
}) const sagaMiddleware = createSagaMiddleware() //生成saga中间件 const store = createStore(reducer, applyMiddleware(sagaMiddleware))
//建立链接
//和thunk一样,把saga中间件挂载到状态管理器中就可以使用saga的方式修改状态了 sagaMiddleware.run(mySaga)
//run: 发送
// 这里是封装了一个mySage函数作为修改状态的函数 export default store

  接下来具体介绍saga如何修改状态

在redux-saga中,修改状态时使用Genarator函数实现的

import { call, put, takeLatest } from 'redux-saga/effects'

import { getBannerList, getProList } from '../api/home'

//  redux-saga    --->    必须与generator函数一起使用

function * getBannerListAction() {
const res = yield call(getBannerList) //call--调用函数
yield put({
type: 'CHANGE_BANNER_LIST',
payload: res.data
})
}
function * getProListAction (action){
const res = yield call(getProList, action.payload)
yield put({
type: 'CHANGE_PRO_LIST',
payload: res.data
})
} function * mySaga () {
yield takeLatest('REQUEST_BANNER_LIST', getBannerListAction)
yield takeLatest('REQUEST_PRO_LIST', getProListAction)
} export default mySaga

  如果看不懂上面,别怕。看这里

// mysaga文件中我们定义了发送的方式
import { takeLatest } from 'redux-saga/effects'
// takeLatest ---分配任务;在下方。我们自己定义了key并为其分配了事件,这些事件就是store.dispatch()函数使用的 function * getProListAction (action){
const res = yield call(getProList, action.payload)
yield put({
type: 'CHANGE_PRO_LIST',
payload: res.data
})
}
function * mySaga () {
yield takeLatest('REQUEST_PRO_LIST', getProListAction)
} // 我们以后再想修改状态的时候就不需要使用store.dispatch()这样修改了
// 可以使用这个文件中定义的key值进行修改 // 我们在组件的connect中这样定义自定义函数,直接根据key值调用这里的修改方法
dispatch => {
dispatch({ type: 'REQUEST_PRO_LIST'})
} // put, call
// call ---> 含义是调用
// put ---> 含义是推,把当前的action推到下一个去执行(队列)。 yield put(action)
yield call(fn)

  以上就是本人结合各种文档对于React常用的状态管理器的一些理解,如果有说错的地方,还希望大家能指出,我们共同进步。

  除了以上这些状态管理器,市面上还有一些工具,MobX,Umi,Dva,这些有时间的话本人也会整理出来与大家共享。

  最后,也希望大家能从这篇文章中收获一些,共勉!

对于React各种状态管理器的解读的更多相关文章

  1. React的状态管理工具

    Mobx-React : 当前最适合React的状态管理工具   MobX 简单.可扩展的状态管理        MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商 ...

  2. react的状态管理

    近两年前端技术的发展如火如荼,大量的前端项目都在使用或转向 Vue 和 React 的阵营, 由前端渲染页面的单页应用占比也越来越高,这就代表前端工作的复杂度也在直线上升,前端页面上展示的信息越来越多 ...

  3. vue状态管理器(用户登录简单应用)

    技术点:通过vue状态管理器,对已经登录的用户显示不同的页面: 一  vue之状态管理器应用 主要用来存储cookie信息 与vue-cookies一起使用 安装:npm install vue-co ...

  4. VueX状态管理器 的应用

    VueX状态管理器 cnpm i vuex axios -S 1 创建Vuex 仓库 import Vue from 'vue' import Vuex from 'vuex' vue.use(Vue ...

  5. react+redux状态管理实现排序 合并多个reducer文件

    这个demo只有一个reducer 所以合并reducer这个demo用不到 ,但是我写出来这样大家以后可以用到,很好用,管理多个reducer,因为只要用到redux就不会只有一个reducer所以 ...

  6. Mobx-React : 当前适合React的状态管理工具

    MobX 简单.可扩展的状态管理        MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商所赞助的.    安装 安装: npm install mobx ...

  7. React + MobX 状态管理入门及实例

    前言 现在最热门的前端框架,毫无疑问是React. React是一个状态机,由开始的初始状态,通过与用户的互动,导致状态变化,从而重新渲染UI. 对于小型应用,引入状态管理库是"奢侈的&qu ...

  8. vue - 状态管理器 Vuex

    状态管理 vuex是一个专门为vue.js设计的集中式状态管理架构.状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态.简单的说就是data中需要共用的属性.

  9. vue项目--vuex状态管理器

    本文取之官网和其他文章结合自己的理解用简单化的语言表达.用于自己的笔记记录,也希望能帮到其他小伙伴理解,学习更多的前端知识. Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态 ...

随机推荐

  1. 【ASP.NET Core】体验一下 Mini Web API

    在上一篇水文中,老周给大伙伴们简单演示了通过 Socket 编程的方式控制 MPD (在树莓派上).按照计划,老周还想给大伙伴们演示一下使用 Web API 来封装对 MPD 控制.思路很 Easy, ...

  2. [hdu6598]Harmonious Army

    网络流建图,首先将所有价值加起来,用最小割考虑要删掉多少个价值:源点向每一个士兵连流量为x的边,士兵向汇点连流量为y的边,每一对关系间连流量为z的边,考虑有方程x1+y2+z=x2+y1+z=a+c, ...

  3. Java 代码审计 — 1. ClassLoader

    参考: https://www.bilibili.com/video/BV1go4y197cL/ https://www.baeldung.com/java-classloaders https:// ...

  4. PIC18 bootloader之UART bootloader

    了解更多关于bootloader 的C语言实现,请加我Q扣: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 应客户要求, 将PIC ...

  5. FMT 和 子集卷积

    FMT 和 子集卷积 FMT 给定数列 $ a_{0\dots 2^{k}-1} $ 求 $ b $ 满足 $ b_{s} = \sum_{i\in s} a_i $ 实现方法很简单, for( i ...

  6. Codeforces 1276D - Tree Elimination(树形 dp)

    Codeforces 题面传送门 & 洛谷题面传送门 繁琐的简单树形 dp(大雾),要是现场肯定弃了去做 F 题 做了我一中午,写篇题解纪念下. 提供一种不太一样的思路. 首先碰到这样的题肯定 ...

  7. LOJ 2372 -「CEOI2002」臭虫集成电路公司(轮廓线 dp)

    题面传送门 u1s1 似乎这题全网无一题解?那就由我来写篇题解造福人类罢(伦敦雾 首先看这数据范围,一脸状压.考虑到每一层的状态与上面两层有关,因此每层转移到下一层的有用信息只有两层,需要用三进制保存 ...

  8. 调用clapack库注意事项

    寒假期间在自己开发的模型DGOM里成功的用clapack替换了MKL,这里就介绍下遇到的几个坑,希望能够帮助别人少走弯路. 1. 调用clapack函数时注意整数类型为integer. 虽然clapa ...

  9. NCBI SRA数据如何进行md5校验?

    下了一些sra数据库中的公共数据,因为pretech和aspera不稳定,稍微大点的文件经常传断,部分文件我只能通过本地下载再上传. 那么问题来了,sra没有md5校验,我怎么知道我数据的完整性,尤其 ...

  10. Xpath解析库的使用

    ### Xpath常用规则 ## nodename 选取此节点的所有子节点 ## / 从当前节点选取直接子节点 ## // 从当前节点选取子孙节点 ## . 选取当前节点 ## .. 选取当前节点的父 ...