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的值都是一致的。
graph LR state1-->A[object tree] state2-->A[object tree] state3-->A[object tree] state4-->A[object tree] A[object tree]-->Store Store-->A[object tree]
  • 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

graph LR Componment--store.dispatch-->Reducer---->Store
Redux的Store

Store就是把action与reducer联系到一起的对象。

  1. 维持应用的state
  2. 提供getState()方法获取state
  3. 提供dispatch()方法发送action
  4. 通过subscribe()来注册监听
  5. 通过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>
            </>
        )
    }
}

小结

  1. 构建action,通过创建一个函数,然后返回一个对象,注意需要携带type助兴
  2. 构建reducer,用来响应action,然后通过return把数据传回给store
  3. 利用createStore来构建store,构建的时候传递我们写好的reducer
  4. 利用store.subscribe()注册监听
  5. 当我们利用store.dispatch()发送一个action的时候就能触发我们的监听了,在里面利用store.getState()就能拿到值
graph TD A[Componment]--dispatch-->B[Reducer] B[Reducer]--return-->C[Store] C[Store]--subscribe-->A[Componment]

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

graph LR A[react-readux Provider]--解决了-->B["容器组件可能存在很深的层级,防止一层一层去传递state"] A[react-readux Provider]--作用-->C["让组件拿到state"] A[react-readux Provider]--原理-->D["react中的context"]

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);

数据调用流程梳理

image

posted @ 2022-03-25 20:39  adminmttt  阅读(97)  评论(0编辑  收藏  举报