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

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

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. (五)MySQL函数

    5.1  常用函数 5.2  聚合函数(常用) 函数名称 描述 COUNT() 计数 SUM() 求和 AVG() 平均值 MAX() 最大值 MIN() 最小值 ....   ....   想查询一 ...

  2. Part 21 to 22 AngularJS anchorscroll

    Part 21 AngularJS anchorscroll example $anchorscroll service is used to jump to a specified element ...

  3. Python基础(filter)

    arr = [1,2,3,1,1,3,6,9] def f1(x): if x > 2: return True arr1 = list(filter(f1,arr)) print(arr1)# ...

  4. pytest-mian函数运行

    1.设置多并发运行 1.命令行安装 pip install pytest-xdist #安装插件,进行多并发运行,#调用:-n -5 import pytest # pytest.main([&quo ...

  5. [bzoj5025]单调上升路径

    由于题目的证明可以发现$ans\ge 2m/n \ge n-1$,于是大胆猜测答案就是n-1若n是奇数,则将边分为n组,每组(n-1)/2,如果同组内边没有交点,那么只需要每一组边一个权值区间,从每一 ...

  6. 既生瑜何生亮 access_token VS refresh_token

    中国有句老话, 既生瑜何生亮, 既然有我周瑜在世, 为什么老天还要一个诸葛亮啊? 同样的, 众所周知, 在 OAuth 2.0 授权协议中, 也有两个令牌 token , 分别是 access_tok ...

  7. AC 自动机学习笔记

    虽然 NOIp 原地爆炸了,目前进入 AFO 状态,但感觉省选还是要冲一把,所以现在又来开始颓字符串辣 首先先复习一个很早很早就学过但忘记的算法--自动 AC AC自动机. AC 自动机能够在 \(\ ...

  8. vector.erase();vector.clear();map.erase();

    vector::erase()返回下一个iter: STL中的源码: //清除[first, last)中的所有元素 iterator erase(iterator first, iterator l ...

  9. 第42篇-JNI引用的管理(1)

    在本地函数中会使用Java服务,这些服务都可以通过调用JNIEnv中封装的函数获取.我们在本地函数中可以访问所传入的引用类型参数,也可以通过JNI函数创建新的 Java 对象.这些 Java 对象显然 ...

  10. 流量限制器(Flux Limiter)

    内容翻译自Wikipedia Flux limiter 流量限制器(Flux limiters)应用在高精度格式中-这种数值方法用来求解科学与工程问题,特别是由偏微分方程(PDE's)描述的流体动力学 ...