最近学习了Redux这个React中的数据管理库,有了一些心得。特此记录~

1.什么是Redux?什么时候我们需要它?

  1. redux是一个专门用于做数据状态管理的JS库,众所周知,由于React是单向数据流,即父组件向子组件可以传递数据,但是反过来就不行。如果我们想要获得兄弟组件的数据,就需要先访问它们共同的父组件。给我们带来了很大的麻烦,于是redux应运而生。
  1. 尽量不用redux,因为redux有一套非常规范的使用流程或者说是模板,给我们带来了记忆上面的成本。
  2. 某个组件的状态需要让所有的组件都能比较轻松访问到才考虑使用。
  3. 一个组件需要改变全局状态或者说一个组件需要改变另一个组件的状态时我们才考虑使用。

2.redux使用流程以及常用api

喜闻乐见地,让我们先上一张很常见的redux流程图。(虽然我知道很难看懂,让我慢慢解释)

首先在这个五颜六色的图里面,最必要的其实只有三个。也就是 ReactComponent(React组件),Store(存放数据的仓库),Reducers(处理各种业务逻辑的仓库管理员,只有管理员才知道怎么处理各种订单),那么就让我们先来看看一个最简单的redux流程要怎么跑通,在这个过程中再解释这些都是干啥的。

  • 我们使用redux的目的,是想要有一个公共的仓库,那里面保存了一些我们想要共享的数据,使得它们可以方便地存储。既然如此我们就要先创建一个新的仓库出来。
npm install --save redux
  • 通过这一段儿代码,我们用npm包管理工具下载下来了redux库,并让它做为我们的运行时依赖。下一步就是新建一个store仓库了。

一般来说,我们需要新建一个文件夹来保存我们的redux文件,在这里我取名为store,在这个文件夹里面新建一个index.js文件,是用来创建store仓库用的。

  • 新建Store的代码

// /Store/index.js
import React from 'react';
import {createStore} from 'redux';const store = createStore(//这里需要一个reducer管理员啦);export default store;
  • 这个时候就引出了store的第一个方法,createStore()--我们可以见名知义地知道这个方法就是用来创建仓库的,一般来说仓库需要一个仓库管理员,这里我们的管理员就是reducer,只是这里我们还没有创建它,接下来我们就来看reducer如何创建并初始化。
// store/reducer.js// 在reducer这个管理员中处理并返回的state会自动修改仓库中的state
// 在这里不允许直接修改state 我们必须要先拷贝出一个副本 在这个副本上修改好了
// 再返回给store最终修改里面的状态 这样子可以防止我们随意操作store里面的数据
// 从而带来一些不可控的后果
// state一旦初始化一次并返回给store后 我们就可以认为后面的state就是store里面的数据const defaultState = {};
export default (state = defaultState,action)=>{return state;
}
  • 这样就完成一个仓库管理员reducer的创建和初始化,可以看到我们的管理员其实就是一个函数,它默认接受两个参数。
  1. 你需要管理什么数据呀(state)?刚开始总得给我指定一个默认的吧(defaultState)
  2. 如果你要操作我仓库里面的数据的话总得告诉我你想做什么操作(action),这个操作有没有特殊要求吧(action)

正所谓巧妇难为无米之炊,我们刚才已经创建了仓库,也有了仓库管理员,接下来就要把仓库管理员放到仓库里面啦~

// /Store/index.js
import React from 'react';
import {createStore} from 'redux';
//引入了reducer
import reducer from './reducer';//传入了reducer
const store = createStore(reducer);export default store;

可以看到,这里比上面只多了两句代码,做的事情也就是把仓库管理员reducer放入仓库里面,让它开始干活儿~

可以说,到了这里。我们仓库有了,管理员也有了。顺理成章地, 我们得试试看它哥俩管不管用啊,那么接下来我们的ReactComponent就该上场啦,ReactComponent啊它是个客户,它可以对仓库发出"订单",这个订单其实就是上面reducer里面的action,action其实是个对象,至于它里面应该有啥,我们待会儿再说。

  • 假设我们现在正在做一个待办列表(TodoList)的应用,我们以增加待办项的代码为例子来解释。
// ./TodoList.js
/*在这个例子里面的defaultSate={inputValue:"",list:['学数学','学英语']}*/import React, {Component} from 'react';
import store from './store/store';export default class TodoList extends React.Component{constructor(props){super(props);// 对该组件的state赋初值// store.getState();此方法调用store里面目前的数据this.state = store.getState();}
handleAdd = ()=>{const action = {type: 'add_item',}// store的方法 意为"发送订单"// 即"客户"ReactComponent给这个store发送订单// 仓库本身无法处理 我们需要仓库管理员来处理// 这也是我们后面要说到的一个重点store.dispatch(action);
}render(){return (<div>...<button onClick={this.handleAdd}>增加</buttton></div>)}}

可以看到我们的"客户"ReactComponent,通过触发事件的形式来给store发订单,国有国法,家有家规。我们写"订单"的时候一定得按照一定的规则去写,这样子会方便管理我们可以视action为这个订单,了解一下我们写订单都要遵循什么规范吧~

  1. 必须有一个type属性,属性值是字符串。这个属性的目的就是告诉reducer管理员你要进行什么操作,写什么可以自己定义。只要做到见名知义即可。
  2. 第二个属性是完成这个操作需要的数据,比如想要删除待办项中的一条总得告诉reducer要删除的是哪一项吧,这个时候就需要要删除待办项的索引了。

只要按照这两个标准写出的action"订单"就是一个合格的"订单",有了订单我们就可以给这个仓库发订单了,要发订单我们使用的是store.dispatch(订单)方法,dispatch在英语里面的意思就是派遣,派发的意思,里面需要传入的你需要派发的订单action,这样子我们在前台做的工作就完成了,我们写好了订单,也给仓库发出了订单,下一步就看仓库那边儿给我们的回应了。

  仓库要做的工作:仓库本身是不能处理订单的,我们需要让管理员来处理,所以这个时候我们的reducer就上场了:

// ./store/reducer.jsimport React from 'react';// 仓库的默认初始状态
const defaultState = {};// 既然仓库管理员redcuer需要处理订单
// 那么就需要两个值 一个是仓库在订单来之前的状态state
// 另一个就是我们的订单了
export default (state=defaultState,action)=>{//在这里我们处理前面发过来的订单if(action.type ==== 'add_item'){// 拷贝一个副本出来 我们作为管理员要先在这个副本上确定好我们要修改什么// 最后再返回给store修改真正的数据// 这个代码是最常见的深拷贝对象一种办法let newState = JSON.parse(JSON.stringify(state));// 在指定的索引处删除一个元素newState.splice(action.index,1);// 最后再返回修改好的状态 到store中自动修改原来的状态return newState;}   // reducer中只要有返回值 就会修改store里面的状态// 但是不能在这里面自己修改store的值return state;}
  • 可以看到上面的代码中通过处理前面发来的订单,"仓库管理员"reducer返回了修改好的新状态,通过这种方式修改了仓库中的数据,到这里"客户"发订单,"管理员"处理订单,最后结果影响仓库的流程就差不多走完了,当然还有最后一步,当状态被修改之后,"客户"要能接收到这个变化。
// ./TodoList.js
/*在这个例子里面的defaultSate={inputValue:"",list:['学数学','学英语']}*/import React, {Component} from 'react';
import store from './store/store';export default class TodoList extends React.Component{constructor(props){super(props);// 对该组件的state赋初值// store.getState();此方法调用store里面目前的数据this.state = store.getState();// 仓库变化时会调用的函数this.storeChange = this.storeChange.bind(this);// 监听仓库的变化store.subscribe(this.storeChange);}storeChange(){// this.setState()方法会调用类里面的render方法// 页面重新渲染this.setState(store.getState());}}
  • store.subscribe(),subscribe在英语里面就是订阅,监听的意思,所以这个函数会在store发生变化时调用你传入的参数,你可以传入一个函数,让store改变时调用它,这个时候一般是调用render函数 或者 自定义一个函数在里面调用setState() 这个方法会自动调用render()。

2. React-Redux---Redux的简化版本

刚才的一整套流程下来虽然很规范,但是总归是流程略显复杂了。给我们记忆上带来不小的麻烦,针对于这样的困扰,有识之士们开发出了一个新的React插件库,React-redux

特点:

  1. 一个 react 插件库
  2. 专门用来简化 react 应用中使用的 redux

在React-redux中提供了一个新标签<Provider>和一个新函数 connect,我们来看看他们都有什么作用:

  • Provider:让所有组件都可以得到 state 数据
import {Provider} from 'react-redux'<Provider store={store}><App />
</Provider>
  • connect():用于包装 UI 组件生成容器组件
import {connect} from 'react-redux'// 用connect包装Counter组件再返回出去
export default connect(mapStateToprops, // 是个回调函数,将状态映射成属性,返回对象mapDispatchToProps // 是个对象,包含actions中的方法(将在内部被转换成调用dispatch的函数)
)(Counter) // 此处填入需要connect函数管理的组件 会映射到这个组件的props上// mapStateToprops() 将store中的state映射到组件的props上
// mapDispatchToprops 将actions中的对象传入connect内部自动帮我们转成一个调用了dispatch的函数,最后再映射到props上,方便我们调用。
  • 下面我们看一个写法:
import {connect} from 'react-redux';
import {addItem} from './store/actions';class TodoList extends React.Component{handleAdd(){this.prpos.addItem();}render(){return (<button onClick={this.handleAdd}/>)}}export default connect(// 此处是个函数 默认被传入了store中的state(state) =>{ inputValue:state.inputValue },// 此处是个函数 默认需要传入action对象 内部帮我们转换成函数,并自动调用dispatch函数{addItem})
  • 上面就是一个常见的react-redux写法,它实际上运用provider和connect,将视图层和业务逻辑分开了,也简化了使用redux的流程,不用我们再一个个调用dispatch函数。

3.Redux异步编程--Redux-Thunk

redux-thunk 增强了actions,以前的actions只能是对象,现在可以是一个函数,那么就可以在这个函数里面写业务逻辑了,比如说异步请求。redux-thunk,是redux的中间件, 中间件的作用我们可以理解为是增强这个库的功能。

  1.thunk的配置

import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'const store = createStore(counter,applyMiddleware(thunk) // 应用异步中间件
)// 如果在浏览器中用了 redux-devTools这个插件 那么如果你想要继续使用 需要额外添加一个增强函数
import { createStore , applyMiddleware ,compose } from 'redux'  //  引入createStore方法
import reducer from './reducer'
import thunk from 'redux-thunk'const composeEnhancers =   window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}):composeconst enhancer = composeEnhancers(applyMiddleware(thunk))const store = createStore( reducer, enhancer) // 创建数据存储仓库
export default store   //暴露出去

   2.应用thunk编写异步程序

export const incrementAsync = (number) => {return dispatch => { // 异步action会返回一个函数// 异步的代码必须被封装到action中setTimeout(() => {// 1s后才去分发一个同步的action(dispatch一个同步action)dispatch(increment(number))}, 1000)}
}
  • 可以看到 thunk为我们封装了dispatch方法这个时候我们可以直接调用。

4.总结

总共讲了三点 

  1. redux使用方法。
  2. react-redux这个简化redux的插件的使用办法。
  3. redux-thunk 这个redux中间件的使用方法。

什么是Redux,如何使用?相关推荐

  1. operate函数_跟着 redux 学 compose组合函数

    ▲ 点击上方蓝字关注我 ▲ 把你的心 我的心串一串 串一株幸运草 串一个同心圆 文 / 景朝霞 来源公号 / 朝霞的光影笔记 ID / zhaoxiajingjing 目录0 / 热热身1 / red ...

  2. Redux 入门教程(三):React-Redux 的用法

    前两篇教程介绍了 Redux 的基本用法和异步操作,今天是最后一部分,介绍如何在 React 项目中使用 Redux. 为了方便使用,Redux 的作者封装了一个 React 专用的库 React-R ...

  3. Redux 入门教程(二):中间件与异步操作

    上一篇文章,我介绍了 Redux 的基本做法:用户发出 Action,Reducer 函数算出新的 State,View 重新渲染. 但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后 ...

  4. Redux 入门教程(一):基本用法

    一年半前,我写了<React 入门实例教程>,介绍了 React 的基本用法. React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案.有两个方面,它没涉及. 代码结构 ...

  5. Koa2和Redux中间件源码研究

    一.Koa2中间件源码分析 在Koa2中,中间件被存放在一个数组中. 使用koa中,最常见的就是app.use(fn),use函数部分源码如下所示.首先中间件必须是个函数.若是generator函数, ...

  6. React+Redux+中间件

    MVVM是Model-View-ViewModel的缩写.mvvm是一种设计思想.Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑:View 代表UI 组件,它负责将数据模 ...

  7. redux rxjs_可观察的RxJS和Redux入门指南

    redux rxjs Redux-Observable is an RxJS-based middleware for Redux that allows developers to work wit ...

  8. redux logic_Redux-Logic简介

    redux logic by Sam Ollason 通过萨姆·奥拉森(Sam Ollason) Redux-Logic简介 (An Introduction to Redux-Logic) This ...

  9. 使用Typescript的巧妙React上下文技巧-不是Redux

    by Bill Girten 比尔·吉尔滕(Bill Girten) 使用Typescript的巧妙React上下文技巧- 不是 Redux (Clever React context tricks ...

  10. redux 局部刷新_如何使用Redux Observables和刷新令牌API获取新的访问令牌

    redux 局部刷新 by Sachin Kumar 由Sachin Kumar 如何使用Redux Observables和刷新令牌API获取新的访问令牌 (How to get a new acc ...

最新文章

  1. mysql 协议的ResultsetRow包及解析
  2. 配置ssh_config
  3. python 开发gui浏览器_Python编程之gui程序实现简单文件浏览器代码
  4. python3遍历技巧
  5. 祁门木板厂深夜失火,及早安装火灾报警器
  6. mysql数据库操作类
  7. WebSocket,不再“轮询”
  8. C++程序设计一、二(二元一次方程与函数、函数指针)
  9. JAVA多线程实现案例
  10. spss26没有典型相关性分析_【spss典型相关分析】数学建模__SPSS_典型相关分析
  11. 直播源码开发,css预加载旋转动画 与 流光字体
  12. 《设计模式》(精华集)
  13. html表格边框默认值,table表格边框的设置
  14. MFC中显示图片(静态、动态)(转)
  15. java生成和解析二维码实战——QRCode
  16. 计算机打印共享应该怎么设置,打印机共享设置,告诉你打印机共享怎么设置
  17. 小公司的大数据基础服务集成平台
  18. (198)ISE14.7生成bit文件压缩方法
  19. 荣耀20android版本10什么意思,手机 篇一:荣耀10的老用户要不要换荣耀20Pro
  20. 通过meta代码强制浏览器使用WebKit内核极速模式(解决 meta name=renderer content=webkit 不起作用)

热门文章

  1. 动网论坛风格php,PHPWIND 论坛模板风格安装教程
  2. 设计模式-04.02-结构型设计模式-门面模式组合模式享元模式
  3. C语言求一元二次方程组的解
  4. Scrapy爬虫框架学习_intermediate
  5. 头部导航(音乐app项目-第1步)
  6. 联想开天s620z改win7和Linux,联想ThinkPad笔记本win10改win7系统及BIOS设置图文教程
  7. 【大学物理实验】冷却法测金属比热容
  8. CoreAnimation中layer动画闪烁的原因及解决
  9. 一分钟经理人精髓记录
  10. checked属性 详解