React训练营:状态管理 redux&react-redux
React概述
1.Redux是一个用于JavaScript状态容器,提供可预测的状态管理。
2.Redux可以用于构建一直化的应用,运行于不同的环境,并且易于测试。
3.Redux除了和React一起使用之外,还支持其他界面库。
JavaScript需要管理更多的数据:服务器响应、缓存数据、本地生成未持久化的数据,也包括UI状态,如果有一个数据模型Model的变化会引起另外一个Model变化,那么当View变化时,就可能引起对应的model以及另一个model变化,依次可能会引起另外的View变化,导致变量的状态混乱,Redux就是为了解决这样的问题。
Redux三大核心
- 单一数据源:整个应用的state被存储在一颗obejct tree中,并且这个object tree只存在于唯一一个store中,保证任何一个页面,拿到State的值都是一致的。
- State是只读的,唯一改变state的方法就是触发action,action是一个用于描述已经发生的普通对象。
store.dispatch([type:'COMPLETE_TODO',index:1])
- 使用纯函数执行修改:为了表述action如何改变state tree,需要编写reducers
Redux的状态
Domain State:可以理解为服务端的数据,比如用户的信息,商品的列表
UI State:决定当前UI展示的状态,弹窗的显示和隐藏,受控组件
App State:全局的状态,请求是否Loading
Redux的Action
Action是本质是一个JS对象,把数据从应用传到store的载体,它是store数据的唯一来源,一般来说,可以通过store.dispatch()将action传递给store
只是描述了事情要发生,并没有描述如何去更新state,在reducer中更新state
Redux的reducer
Reduer本质就是一个函数,用来响应发过来的action,然后经过处理,把state发送给Store
Redux的Store
Store就是把action与reducer联系到一起的对象。
- 维持应用的state
- 提供getState()方法获取state
- 提供dispatch()方法发送action
- 通过subscribe()来注册监听
- 通过subscribe()的返回值来注销监听
实战
1.创建组件Button用于发送Action
import React from "react";
export default class ReduxDemo extends React.Component{
render(){
return (
<button>点我发送一个Action</button>
)
}
}
2.创建Action.js
export const sendAction = ()=>{
//构建Action
return {
type:"SEND ACTION",
value:"发送了一个Action"
}
}
3.创建Reducer.js
const initState = {value:"默认值"}
export const reduxDemoReducer = (state=initState,action)=>{
switch (action.type) {
case "SEND ACTION":
return Object.assign({}, state, action);
default:
return state;
}
}
4.创建Store
import {createStore} from 'redux';
import { reduxDemoReducer } from '../redux/reduxDemo/reducers';
export const store = createStore(reduxDemoReducer);
使用Redux
给页面的Button按钮绑定一个点击事件
在组件加载完成的时候通过store来进行监听器的注册,返回值可以用来注销监听
import React from "react";
//导入Store
import { store } from "../../infrastrucure/store";
//导入action 构建函数
import { sendAction } from "../../infrastrucure/redux/reduxDemo/actions";
export default class ReduxDemo extends React.Component{
handleClick = () =>{
const action = sendAction();
//发送一个action
store.dispatch(action)
};
//当组件加载完毕的时候进行监听
componentDidMount(){
store.subscribe(()=>{
console.log("ReduxDemo",store.getState())
//用于刷新组件的状态
this.setState({});
})
}
render(){
return (
<>
<button onClick={this.handleClick}>点我发送一个Action</button>
<div>{JSON.stringify(store.getState())}</div>
</>
)
}
}
小结
- 构建action,通过创建一个函数,然后返回一个对象,注意需要携带type助兴
- 构建reducer,用来响应action,然后通过return把数据传回给store
- 利用createStore来构建store,构建的时候传递我们写好的reducer
- 利用store.subscribe()注册监听
- 当我们利用store.dispatch()发送一个action的时候就能触发我们的监听了,在里面利用store.getState()就能拿到值
React-redux
如何设置全局Store,避免一直写上述的1~5的步骤?
React-redux,Redux和React没有关系,Redux支持React、Angular....
react-redux就是官方出品的用于配合React的绑定库,能够使React组件从Redux store中方便地读取数据,并且向store中分发actions以此来更新数据。
React-Redux中两个重要的成员:Provider-->能够使得整个App都能获取到store中的数据,connect 能够使得组件和store进行关联。
Provider、connect
Provider包裹在根组件最外层,使所有的子组件都能拿到State
Provider接收store作为props,然后通过context往下传递,这样react中任何组件都可以通过context获取到store
connect Provider内部组件如果想要使用到state中的数据,就必须要connect进行一层包裹封装,换言之,就必须要被connect加强
connect 方便我们组件能够获取到store中的state
参数名 | 类型 | 说明 |
---|---|---|
mapStateToProps(state,ownProps) | Function | 这个函数允许我们将store中的数据作为props绑定到组件上,state:Redux中的store,ownProps:自己的props |
mapDispatchToProps(dispatch,ownProps) | Function | 将action作为props绑定我们自己的函数中,dispatch:就是store.dispatch(),ownProps:自己的props |
mergeProps(stateProps,dispatchProps,ownProps | Function | 不管是stateProps还是dispatchProps,都需要和ownProps merge之后才会被赋给我们的组件,通常情况下,可以不传递这个参数,connect就会使用Object.assign替代该方法 |
options | Object | 可以定制connector的行为 |
React-redux,发送数据与接收数据
1.编写reducer
const initState = {
count:1
}
//reducer 要就接收Action,然后进行逻辑处理
//判断Action是否我们所需要
//如果是,那么return 一个新的state
export const plusOne = (state=initState,action)=>{
console.log('reducer:',action)
switch (action.type) {
case 'ADD ACTION':
return {
count: state.count+1
};
default:
return state;
}
}
2.消息发送方
import React from "react";
//1.导入connect
import { connect } from "react-redux";
class PlusOne extends React.Component{
//4.组件中使用
handlClick=()=>{
console.log("PlusOne", this.props);
//发送Action
this.props.sendAction();
};
render(){
return (
<button onClick={this.handlClick}>PlusOne</button>
);
}
}
/**
* 3.实现connect的第二个参数,用来发送action,这个函数的返回值是一个对象
* { key: 方法名, value:调用dispatch}
* @param {*} dispatch
*/
const mapDispatchToProps=(dispatch)=>{
return {
sendAction:()=>{
//利用dispatch发送一个action,传递action对象,要定义一个type属性
dispatch({
type:'ADD ACTION'
})
}
}
};
//PlusOne为消息发送方,2.组件加强
//connect(要接受数据的函数,要发送action的函数)(放入要加强的组件)
export default connect(null,mapDispatchToProps)(PlusOne);
3.消息接收方
import React from "react";
import { connect } from "react-redux";
class PrintDemo extends React.Component{
render(){
console.log("PrintDemo:",this.props)
return (
<>
<div>
组件PrintDemo
</div>
<div>
{this.props.count}
</div>
</>
);
}
}
/**
* 接收两个参数
* @param {*} state
*/
const mapStateToProps=(state)=>{
console.log("PrintDemo",state)
return state;
}
//PrintDemo组件的接收方
export default connect(mapStateToProps)(PrintDemo);