redux是一个专门用于做状态管理的JS库(不是react插件库),可以用在react、angular、vue等项目中,能够集中式管理react应用中多个组件共享的状态。
redux开发者工具:
在Google应用商店搜索Redux DevTools
使用场景:

动作的对象。
包含两个属性:
{
type: 'ADD_PERSON',
data: {
name: '张三',
age: 12
}
}
用于初始化状态、加工状态。
加工时会根据旧的state和action来产生新的state的纯函数。
redux的reducer函数必须是一个纯函数。
将state、action和reducer联系在一起的对象。
得到此对象:
import {createStore} from 'index'import reducer from './reducersconst store = createStore(reducer)此对象的功能:
getState():得到statedispatch(action):分发action,触发reducer,产生新的statesubscribe(listener):注册监听,当产生了新的state时,自动调用用于创建包含指定reducer的store对象
createStore已弃用
store对象是redux库最核心的管理对象。
store对象内部维护:
核心方法:
具体编码:
应用上基于redux的中间件(插件库)
合并多个reducer函数
想做一个求和案例:
安装redux:npm install redux
在src目录下新建redux目录,并创建store.js和count_reducer.js(转为求和服务的reducer文件)文件

/**
* 该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
// 引入legacy_createStore,用于创建redux中最为核心的store对象
import { legacy_createStore } from 'redux'
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 暴露store
export default legacy_createStore(countReducer)
初始化时,preState的值为undefined,action中的type为@@init形式的值,没有data
/**
* 该文件用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
* reducrt函数接收两个参数,分别为:之前的状态和动作对象
*/
// 初始化状态
const initState = 0
export default function countReducer(preState = initState, action) {
// 从action对象中获取 type、data
const { type, data } = action
// 根据 type 决定如何加工数据
switch (type) {
case 'increment': // 加
return preState + data
case 'decrement': // 减
return preState - data
default:
return preState
}
}
import React, { Component } from 'react';
import './index.css'
export default class Count extends Component {
state = {
count: 0
}
increment = () => {
const { value } = this.selectNumber
const { count } = this.state
this.setState({
count: count + value * 1
})
}
decrement = () => {
const { value } = this.selectNumber
const { count } = this.state
this.setState({
count: count - value * 1
})
}
incrementIfOdd = () => {
const { value } = this.selectNumber
const { count } = this.state
if (count % 2 !== 0) {
this.setState({
count: count + value * 1
})
}
}
incrementAsync = () => {
const { value } = this.selectNumber
const { count } = this.state
setTimeout(() => {
this.setState({
count: count + value * 1
})
}, 500);
}
render() {
return (
<div>
<h1>当前求和为:{this.state.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数时+</button>
<button onClick={this.incrementAsync}>异步+</button>
</div>
);
}
}
import React, { Component } from 'react';
import './index.css'
import store from '../../redux/store';
export default class Count extends Component {
// 去除Count组件自身的状态
// state = {
// count: 0
// }
// 可以直接在入口文件中写,当多个组件使用redux时,只需写一次就能实现状态更新时组件自动更新
// componentDidMount() {
// /**
// * redux只负责状态管理,状态更改并不会引起组件更新
// * 需要监测redux中状态的变化,只要变化,就调用render
// */
// store.subscribe(() => {
// this.setState({})
// })
// }
increment = () => {
const { value } = this.selectNumber
// 通知 redux 加 value
store.dispatch({ type: 'increment', data: value * 1 })
}
decrement = () => {
const { value } = this.selectNumber
store.dispatch({ type: 'decrement', data: value * 1 })
}
incrementIfOdd = () => {
const { value } = this.selectNumber
const count = store.getState()
if (count % 2 !== 0) {
store.dispatch({ type: 'increment', data: value * 1 })
}
}
incrementAsync = () => {
const { value } = this.selectNumber
setTimeout(() => {
store.dispatch({ type: 'increment', data: value * 1 })
}, 500);
}
render() {
return (
<div>
<h1>当前求和为:{store.getState()}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数时+</button>
<button onClick={this.incrementAsync}>异步+</button>
</div>
);
}
}

export const createIncrementAction = data => ({ type: 'increment', data })
export const createDecrementAction = data => ({ type: 'decrement', data })

action的值可以是一般对象Object(同步) 或 函数function(异步)。
redux默认是不能进行异步处理的,但某些时候应用中需要在redux中执行异步任务(ajax, 定时器)。
例子:将组件中的异步任务交到action中去实现:
store默认action必须是一个Object类型的一般对象,所以需要通过一个中间件来使用异步action
可以使用异步中间件:npm install --save redux-thunk
在store.js中引入异步中间件



不过此时这个函数已经是store帮忙调用的,可以不用引入store
异步action中一般都会调用同步action

react-redux是一个react插件库,专门用来简化react应用中使用redux。
- UI组件
- 只负责 UI 的呈现,不带有任何业务逻辑
- 通过props接收数据(一般数据和函数)
- 不使用任何 Redux 的 API
- 一般保存在components文件夹下
- 容器组件
- 负责管理数据和业务逻辑,不负责UI的呈现
- 使用 Redux 的 API
- 一般保存在containers文件夹下
UI组件都会被容器组件包裹,由容器组件与redux打交道,且容器组件可以随意使用redux的API,而UI组件中则不能使用任何redux的API。
容器组件给UI组件传:(都通过props传递)

Provider:让所有组件都可以得到state数据
connect:用于包装 UI 组件生成容器组件
mapStateToprops:将外部的数据(即state对象)转换为UI组件的标签属性
mapDispatchToProps:将分发action的函数转换为UI组件的标签属性
使用:
import React, { Component } from 'react'
import './index.css'
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber
}
decrement = () => {
const { value } = this.selectNumber
}
incrementIfOdd = () => {
const { value } = this.selectNumber
}
incrementAsync = () => {
const { value } = this.selectNumber
}
render() {
return (
<div>
<h1>当前求和为:?</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数时+</button>
<button onClick={this.incrementAsync}>异步+</button>
</div>
);
}
}
src -> containers -> Count -> index.jsxnpm i react-redux/**
* 容器组件作为UI组件和redux的桥梁,需要将两者引入
*/
// 引入Count的UI组件
import CountUI from '../../components/Count'
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
// 引入connect用于连接UI组件和redux
import { connect } from 'react-redux'
/**
* mapStateToProps函数返回一个对象
* 返回的对象中的key就作为传递给了UI组件props的key
* 返回的对象中的value就作为传递给了UI组件props的value
* 用于传递状态
*/
// function mapStateToProps(state) {
// return { count: state }
// }
const mapStateToProps = (state) => ({ count: state })
/**
* mapDispatchToProps函数返回一个对象
* 返回的对象中的key就作为传递给了UI组件props的key
* 返回的对象中的value就作为传递给了UI组件props的value
* 用于传递操作状态的方法
*/
// function mapDispatchToProps(dispatch) {
// return {
// add: (data) => {
// // 通知redux执行加法
// dispatch(createIncrementAction(data))
// },
// des: (data) => {
// // 通知redux执行减法
// dispatch(createDecrementAction(data))
// },
// addAsync: (data, time) => {
// // 异步加
// dispatch(createIncrementAsyncAction(data, time))
// }
// }
const mapDispatchToProps = (dispatch) => ({
add: (data) => {
// 通知redux执行加法
dispatch(createIncrementAction(data))
},
des: (data) => {
// 通知redux执行减法
dispatch(createDecrementAction(data))
},
addAsync: (data, time) => {
// 异步加
dispatch(createIncrementAsyncAction(data, time))
}
})
}
// 使用connent创建并暴露Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)

import React, { Component } from 'react'
import './index.css'
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber
this.props.add(value * 1)
}
decrement = () => {
const { value } = this.selectNumber
this.props.des(value * 1)
}
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.add(value * 1)
}
}
incrementAsync = () => {
const { value } = this.selectNumber
this.props.addAsync(value * 1, 500)
}
render() {
// console.log(this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数时+</button>
<button onClick={this.incrementAsync}>异步+</button>
</div>
);
}
}
mapDispatchToProps可以简写,因为react-redux做了自动分发

index.js文件中不再需要监测redux状态发生改变,容器组件中已经默认拥有监测redux状态发生改变的能力
// 检测redux中状态改变,若redux状态发生改变,则重新渲染App组件
// store.subscribe(() => {
// ReactDOM.render( , document.getElementById('root'))
// })


import React, { Component } from 'react'
import '../../components/Count/index'
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
// 引入connect用于连接UI组件和redux
import { connect } from 'react-redux'
// 定义UI组件
class Count extends Component {
increment = () => {
const { value } = this.selectNumber
this.props.add(value * 1)
}
decrement = () => {
const { value } = this.selectNumber
this.props.des(value * 1)
}
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.add(value * 1)
}
}
incrementAsync = () => {
const { value } = this.selectNumber
this.props.addAsync(value * 1, 500)
}
render() {
// console.log(this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数时+</button>
<button onClick={this.incrementAsync}>异步+</button>
</div>
);
}
}
// 使用connent创建并暴露Count的容器组件
export default connect((state) => ({ count: state }), {
add: createIncrementAction,
des: createDecrementAction,
addAsync: createIncrementAsyncAction
})(Count)