Redux
认识:redux是一个独立专门用于做状态管理的JS库(不是react插件库)
使用步骤
1.创建reducer
可以使用单独的一个reducer,也可以将多个reducer合并为一个reducer,即:conbineReducers()
action发出命令后将state放入reducer加工函数中,返回新的state,对state进行加工处理
2.创建action
用户是接触不到state的,只能由view触发,所以,这个action可以理解为指令,需要发出多少动作就有多少指令
action是一个对象,必须有一个叫type的参数,定义action类型
异步action需借助第三方库redux-thunk 并结合applyMiddleware使用
import{creareStore,applyMiddleware}from ‘redux’
import thunk from ‘redux-thunk’
const store=createStore(**Reducer,applyMiddleware(thunk))
3.创建store,使用createStore方法
store可以理解为有多个加工机器的工厂
提供subscribe、dispatch、getState这些方法
实践
reducer
/*
1、该文件是用于创建一个Count组件服务的reducer,reducer的本质就是一个函数
2、reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
3、reducer被第一次调用时,是store自动触发的,传递的preState是undefined,传递的action是类似于:{
type: '@@REDUX/INIT_a.2.b.4'
}
*/
const {INCREMENT, DECREMENT} from './constant'
const initState = 0;//初始化状态,推荐写法
export default function countReducer (preState = initState, action) {
//if(preState === undefined) preState = 0
//从action对象中获取:type、data
const { type, data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT://如果是加
return preState + data;
case DECREMENT://如果是减
return preState - data;
default:
return preState
}
action
/*
该文件专门为Count组件生成action对象
*/
function createIncrementAction(data) {
return {
type:'increment',
data
}
}
function createDecrementAction(data) {
return {
type:'decrement',
data
}
}
//改造之后
const {INCREMENT, DECREMENT} from './constant'
//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
//函数体
dispatch(createDecrementAction(data));
},time)
}
}
综合
//引入store,用于获取redux中保存的状态
import store from '../../redux/store'
//引入actionCreator专门用于创建action对象
import {createIncrementAction,createDecrementAction,createIncrementAsyncAction} from '../../redux/count_action'
//componentDidMount() {
//监测redux中状态的变化,只要变化,就调用render
//store.subscribe(() => {
//this.setState({})
//})
//}
//加法
increment = () => {
const { value } = this.selectNumber;
//store.dispatch({type:'increment', date : value * 1});
store.dispatch(createIncrementAction(value * 1));
}
//减法
decrement = () => {
const { value } = this.selectNumber;
//store.dispatch({type:'decrement', date : value * 1});
store.dispatch(createDecrementAction(value * 1));
}
//奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber;
const count = store.getState();
if (count % 2 !== 0) {
//store.dispatch({type:'increment',data : value * 1})
store.dispatch(createIncrementAction(value * 1));
}
}
incrementAsync = () => {
const { value } = this.selectNumber;
store.dispatch(createIncrementAsyncAction(value * 1 , 500))
}
render() {
return (
<div>
<h1>当前和为: {store.getState()}</h1>
</div>
)
}
监测redux中状态的改变,如redux的状态发生了变化,那么重新渲染App组件
import React from "react";
import ReactDOM from "react-dom";
import App from './App';
import store from './store/store';
ReactDOM.render(<App/>,document.getElementById('root'))
// 在这里需要明确的是:redux只是一个状态的管理机制,它不会自动的触发页面的更新,需要我们自己去写
store.subscribe(() => ReactDOM.render(<App/>,document.getElementById('root')))
redux小结
createStore:创建包含指定reducer的store对象
store对象:redux库最核心的管理对象,内部维护着state、reducer
applyMiddleware:应用上基于redux的中间件(redux不支持异步更新,只支持同步数据的修改)
combineReducers:合并多个reducer函数
react-redux
注意事项
1.所有的UI组件都应该包裹一个容器组件,他们是父子关系
2.容器组件是真正和redux打交道的,里面可以随意的使用redux的api
3.UI组件不能使用任何的redux的api
4.容器组件会传给UI组件
1.redux中保存的状态
2.用于操作状态的方法
5.容器组件给UI组件的状态、方法均通过props传递
两个核心
Provider
可参考redux的store.subscribe()方法,,简单来说就是提供一个顶级的组件,将整个应用进行控制。这里的Provider也是类似的功能,并且将整个store作为参数传入了应用
<Provider store={sotre}>
<App/>
</Provider>
这样所有的组件就能访问redux的数据了
connect----连接容器组件与UI组件的桥梁
语法 connect(需传递的redux状态或者方法)(UI组件)
实践
//引入Count 的ui组件
import CountUI from '../../components/Count'
//引入connect用于连接UI组件与redux
import {connect} from 'react-redux';
import {createIncrementAction} from 'action';
/*
1、mapStateToProps函数返回的是一个对象;
2、对象中的key就作为传递给Ui组件props的key,value就作为传递给Ui组件props的value
3、mapStateToProps用于传递状态
*/
function mapStateToProps(state) {
return {
count:state
}
}
/*
1、mapDispatchToProps函数返回的是一个对象;
2、对象中的key就作为传递给Ui组件props的key,value就作为传递给Ui组件props的value
3、mapDispatchToProps用于传递操作状态的方法
*/
function mapDispatchToProps(dispatch) {
return {
jia:(data) => {
//通知redux执行加法
dispatch(createIncrementAction(number))
}
}
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from './redux/store';
import { Provider} from 'react-redux';
ReactDOM.render(
//此处需要用Provider包裹App,目的是让App所有的后代容器组件都可以接收到store
<Provider store = {store}>
<App />
</Provider>,
document.getElementById('root')
优化
1、容器组件和Ui组件整合一个文件;
2、无需自己给容器组件传递store,给<App />包裹一个<Provider store = {store} />即可;
3、使用了react-redux后也不用再给自己检测redux状态的改变了,容器组件可以自动完成这个工作;
4、mapDispatchToProps可以简单的写成一个对象
5、一个组件要和redux打交道,要经过哪几步?
(1)定义好ui组件--不暴露;
(2)引入connect生成一个容器组件,并暴露,写法如下:
connect(
state=({type:value}),
{key:xxxAction}
)(UI组件)
(3)在ui组件中通过this.props.xxx读取和操作状态