什么是Redux?
Redux是一个JavaScript应用状态管理的库,当项目很复杂的时候,属性传递已经达不到我们预期,可以使用Redux解决数据传递问题,统一状态管理。换句话说,Redux就是用来处理和管理应用的状态/数据

redux是一个独立专门用于做状态管理的JS库

例子:如果要进行加一操作流程如下:

核心概念
Store(存储数据)
在redux里面,只有一个Store,整个应用需要管理的数据都在这个Store里面。这个Store我们不能直接取改变,我们只能通过返回一个新的Store去更改它。redux提供了一个createStore来创建state
1
2
|
import { createStore } from 'redux';
const store = createStore(reducer);
|
action(方法:type名称,payload参数)
这个action指的是视图层发起的一个操作,告诉Store我们需要改变。比如用户点击了按钮,我们就要去请求列表,列表的数据就会变更。每个action必须有一个type属性,这表示action的名称,然后还可以有一个payload属性,这个属性可以带一些参数,用作Store变更:
1
2
3
4
|
const action = {
type: 'ADD_ITEM',
payload: 'new item',//可选属性
}
|
dispatch(发出action)
在上面我们定义了一个Action,但是Action不会自己主动发出变更操作到Store,所以这里我们需要一个叫dispatch的东西,它专门用来发出action,不过还好,这个dispatch不需要我们自己定义和实现,redux已经帮我们写好了,在redux里面,**store.dispatch()**是View发出Action的唯一方法
1
2
3
4
|
store.dispatch({
type:'ADD_ITEM',
payload:'new item', //可选属性
})
|
Reducer(计算新的store的)
当dispatch发起了一个action之后,会到达reducer,那么这个reducer用来干什么呢?顾名思义,这个reducer就是用来计算新的store的,reducer接收两个参数:当前的state和接收到的action,然后它经过计算,会返回一个新的state。(不能直接更改state,必须通过返回一个新的state来进行变更。)
1
2
3
4
|
const reducer=function(prevState,action){
...
return newState
}
|
State(数据集合)
store某个节点对应的数据集合就是state。state是被托管的数据,也就是每次出发监听事件,我们要操作的数据。可以通过store.getState()获得:store.getState()即可获取到reducer中的state
1
2
|
let store=createStore(fn);
let state=store.getState();
|
Redux核心API
引入必要组件:
1
|
import {createStore} from 'redux'
|
生成store:
1
|
const store=createStore(reducer,state初始状态[可选]);
|
取得当前时刻的state:
1
|
const state=store.getState();
|
发出action:
1
2
3
4
|
store.dispatch({
type:'ADD_TODO',
text:'Learn Redux',
})
|
Reducer函数里面不能改变State,必须返回一个全新的对象,请参考下面的写法。
1
2
3
4
5
6
7
8
9
10
|
//State是一个对象
function reducer(state, action) {
return Object.assign({}, state, { thingToChange });
//或者
return { ...state, ...newState };
}
//State是一个数组
function reducer(state, aciton) {
return [...state, newItem];
}
|
Redux的优势
没使用redux:

使用redux:

Redux使状态可预测
在Redux中,状态始终是可预测的。如果将相同的状态和动作传递给减速器,则总是会产生相同的结果,因为减速器是纯函数。状态也是不可变的,永远不会改变。这使得执行诸如无限撤销和重做之类的艰巨任务成为可能。还可以在之前的状态之间来回移动并实时查看结果
Redux是可维护的
Redux的写法比较固定,团队应用中风格比较稳定,提高协作中的可维护性
Redux调试简单
在控制台中使用Redux Dev Tools
性能优势
我们可能会假设保持应用程序的状态全局会导致一些性能下降。在很大程度上,情况并非如此,因为React Redux在内部实现了许多性能优化,因此我们自己的连接组件仅在实际需要时才重新渲染
易于测试
由于函数用于更改纯函数的状态,因此测试Redux应用程序很容易
状态持久化
我们可以将应用程序的一些状态持久化到本地存储并在刷新后恢复它。
服务端渲染
Redux也可以用于服务端渲染。有了它,我们可以通过将应用程序的状态连同它对服务器请求的响应发送到服务器来处理应用程序的初始呈现。然后所需的组件以HTML格式呈现并发送到客户端
实战项目
安装redux
1
|
npm install redux --save
|
Redux的简单使用
(1)新建store
(2)获取状态:
读取:store.getState()即可获取到reducer中的state
(3)派发事件:
修改: store.dispatch(action)通过dispatch一个action来出发reducer中的修改行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import { createStore } from 'redux';
//1.新建store
//通过reducer建立
//根据老的state和action生成新的state
function counter(state = 0, action) {
switch (action, type) {
case 'addGun':
return state + 1;
case 'removeGun':
return state - 1;
default:
return 10;
}
}
//1. 新建store
const store = createStore(counter);
//2.获取状态
const init = store.getState();
function listener() {
const current = store.getState();
console.log(`现在的个数${current}`);
}
//每次派发事件之后,都会调用,进而获取状态
store.subscribe(listener);
//3.派发事件
store.dispatch({ type: 'addGun' });
store.dispatch({ type: 'addGun' });
store.dispatch({ type: 'removeGun' });
|
输出:现在的个数11现在的个数12现在的个数11
react与redux组合使用
安装redux-thunk,解决异步问题
1
|
npm install redux-thunk --save
|
(1)把store.dispatch方法传递给组件,内部可以调用修改状态
(2)subscribe订阅render函数,每次修改都重新渲染
(3)redux相关的内容,移动到单独的文件index.redux.js单独管理
(4)npm install redux-thunk –save解决异步请求的问题
(5)使用apply/Middleware开启thunk中间件
步骤一:在src下新建App.js、index.redux.js,在index.js中负责页面结构的组建、store的建立
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import React from 'react';
import ReactDom from 'react-dom';
import App from './App';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { counter } from './index.redux';
import { addGun, removeGun, addGunAsync } from './index.redux';
//applyMiddleware可以使用异步操作
const store = createStore(counter, applyMiddleware(thunk));
function render() {
ReactDom.render( <App store = {store} addGun = {addGun} removeGun = {removeGun} addGunAsync = {addGunAsync}/>,document.getElementById('root'))
}
render()
//监听状态的变化,每次重新渲染组件
store.subscribe(render)
|
步骤二:在App.js中完成组件内容的编写、页面的渲染以及相关事件的派发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import React from 'react';
class App extends React.component {
//constructor(props){
//super(props)
//}
render() {
//接收从父组件index.js中传过来的store
const store = this.props.store;
//获取机枪数量状态的变化
const num = store.getState();
//通过组件传递action,降低耦合度
const addGun = this.props.addGun;
const removeGun = this.props.removeGun;
const addGunAsync = this.props.addGunAsync;
return (
<div>
<h2> 现在有机枪 { num } </h2>
{/* 当点击按钮时执行事件的派发,即调用action */}
<button onClick={()=>store.dispatch(addGun())}>申请武器</button>
<button onClick={()=>store.dispatch(removeGun())}>回收武器</button>
<button onClick={()=>store.dispatch(addGunAsync())}>延迟回收武器</button>
</div >
)
}
}
export default App
|
步骤三:index.redux.js中负责的store中对状态变化的处理、action事件的编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
const ADD_GUN = 'addGun';
const REMOVE_GUN = 'removeGun';
//store
export function counter(state = 0, action) {
//当action被调用执行时,会到此处进行判断,执行状态的变化
switch (action.type) {
case 'addGun':
return state + 1;
case 'removeGun':
return state - 1;
default:
return 10;
}
}
//action
export function addGun() {
return { type: ADD_GUN }
}
export function removeGun() {
return { type: REMOVE_GUN }
}
export function addGunAsync() {
return dispatch => {
setTimeout(() => {
dispatch(addGun())
}, 2000)
}
}
|
Redux使用的解耦(react与redux自动连接)
redux-thunk
(1)基本介绍
- redux-thunk改写了dispatch API,使其具备接受一个函数作为参数的能力,从而达到middleware的效果,即在redux的dispatch action=>reducer=>store这个流程中,在action被发起之后,到达reducer之前的扩展点,加入相关操作,比如发生请求、log信息等
- 提供Redux的异步解决方案,弥补Redux功能的不足
