什么是Redux
2013年 Facebook 提出了 Flux 架构的思想,引发了很多的实现。2015年,Redux 出
现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。
Redux的官方解释是:Redux is a predictable state container for JavaScript apps. 意思
就是Redux是js应用的一种可预测的状态容器。
此处需要说明的是flux和redux与 react都没有关系,redux和flux可以用在任何框架中,因
为flux和redux是完整的架构,使用react开发项目的时候,只是将react的组件作为redux
中的视图层去使用。
react设计理念是单向数据流,而我们在用react构建前端应用的时候,通常需要获取其他
组件的状态,如果组件繁多,获取修改其状态就比较麻烦,这时候就用到了redux。
Redux组成部分
store:数据的管理者和数据的存储者;
actionCreators:动作的创建者,发送动作给reducers
react Components:react组件,用来充当视图层
reducers:数据的修改者,返回一个新的newstate给store,它是一个纯函数
为什么使用Redux
React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没
涉及。
(1)代码结构
(2)组件之间的通信
没有使用Redux的情况,如果两个组件(非父子关系)之间需要通信的话,可能需要多个中
间组件为他们进行消息传递,这样既浪费了资源,代码也会比较复杂。
Redux中提出了单一数据源Store 用来存储状态数据,所有的组建都可以通过Action修改
Store,也可以从Store中获取最新状态。使用了redux就可以完美解决组建之间的通信问题。
Redux的使用的三大原则:
(1)Single Source of Truth(唯一的数据源)
(2)State is read-only(状态是只读的)
(3)Changes are made with pure function(数据的改变必须通过纯函数完成)
Redux使用场合
如果你不知道是否需要 Redux,那就是不需要它,只有遇到 React 实在解决不了的问
题,你才需要 Redux。
简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加
复杂性,比如:
(1)用户的使用方式非常简单
(2)用户之间没有协作
(3)不需要与服务器大量交互,也没有使用 WebSocket
(4)视图层(View)只从单一来源获取数据
但是如果你开发的项目,满足下面的条件,那么这时候就需要Redux登场了:
(1)用户的使用方式复杂
(2)不同身份的用户有不同的使用方式(比如普通用户和管理员)
(3)多个用户之间可以协作
(4)与服务器大量交互,或者使用了WebSocket
(5)View要从多个来源获取数据
从组件层面考虑,满足下列要求,就需要使用Redux:
(1)某个组件的状态,需要共享
(2)某个状态需要在任何地方都可以拿到
(3)一个组件需要改变全局状态
(4)一个组件需要改变另一个组件的状态
Redux的使用
下面以一个计数案例来说明redux的具体使用流程
(1)安装redux
yarn add redux
(2)在src文件夹下新建store文件夹(此处默认使用create-react-app已安装好项目),
然后在store文件夹中,新建index.js、reducers.js、actionCreators.js、state.js文件
(3)分别打造上面三个文件
state.js–存放数据
const state={
num:0
}
export default state
reducers.js–是一个纯函数
//1.该函数有两个参数
//第一个参数是唯一数据源,需要赋值初始数据,第二个参数是actionCreators中发来的动作action
//2.拷贝一层数据源,进行这个数据源的修改
//3.返回值:返回新的状态
//4.使用switch,判断用户的动作类型,进行对应的数据修改
import state from './state'
const reducers=(prevState = state , action)=>{
//拷贝初始数据,生成新的状态值
const newState={
...prevState
}
return newState//返回拷贝出来的新的值
}
export default reducers
index.js
import { createStore } from 'redux'
import reducer from './reducers'
const store = createStore( reducer )
export default store
(4)在你想要的组件中直接引用store
import React, { Component } from 'react';
import store from '../store'//引入store中的数据
console.log(store.getState())
class Count extends Component {
constructor(props) {
super(props);
this.state = {
count:store.getState().num//将store中的数据赋给count
}
}
render() {
return (
<div>
<button>+</button>
<p>num:{this.state.count}</p>//展示数据
</div>
);
}
}
export default Count;
(5)打造actionCreators.js文件
// 创建动作,并发送动作,引入动作的类型
import * as type from './type'
import store from './index'//引入store,为了使用store中的dispatch方法来发送动作
console.log(store)
const actionCreators={
increasement( val ){//此处的val来自于组件调用该方法时,传递过来的参数
let action={//定义动作
type:type.INCREASEMENT,
payload:val//该负载可有可无,根据组件在调用increasement方法时是否传递参数来决定
}
store.dispatch(action)//发送动作
}
}
export default actionCreators
(6)在reducer.js中根据动作类型,对数据进行操作
import state from './state'
import * as type from './type'
const reducers=(prevState = state , action)=>{
//拷贝初始数据,生成新的状态值
const newState={
...prevState
}
switch (action.type) {
case type.INCREASEMENT:
console.log(action)//此处有输出action,那么说明在actionCreator中定义的动作,已成功
newState.num++
break;
default:
break;
}
return newState
}
export default reducers
(7)最后在组件中【此处是react中的组件】使用actionCreators.js中的方法即可
import React, { Component } from 'react';
import store from '../store'
import actionCreators from '../store/actionCreators'
console.log(store.getState())
class Count extends Component {
constructor(props) {
super(props);
this.state = {
count:store.getState().num
}
}
add=()=>{
actionCreators.increasement('hello')//此处的hello就是传递给actionCreators.js中的val
//可根据需要传递改参数,
}
componentDidMount(){
//视图的更新,需要事件的发布和订阅,在redux中不需要写事件的发布,
//只需要写订阅,store中的subscribe的方法,就是订阅,将数据的修改写在
//subscribe中的回调函数内部
store.subscribe(()=>{
this.setState({
count:store.getState().num
})
})
}
render() {
return (
<div>
<button onClick={this.add}>+</button>
<p>num:{this.state.count}</p>
</div>
);
}
}
export default Count;