react-总结10-状态管理-flux-redux-mobx

React状态管理

1.作用:实现多组件状态共享,也是组件通信的一个方案
2.React状态管理

	-Flux 目前很少人用了  是其他状态管理的基础
	-Redux 最流行的形式
	-mobx 前卫的形式

3.React是一个视图层框架,可以认为是单纯的MVC中的V

Flux

Flux是一种软件架构思维,后期发展改进,诞生了Redux,在Flux的架构思维中,React只是其中的一部分,V

Flux的组成部分

  • View:视图层(React)
  • ActionCreators(动作创建者):视图层发出的消息(如点击事件)
  • Dispatcher(派发器):用来接收Actions、执行回调函数
  • Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面
    在这里插入图片描述
    流程想要使用Flux架构思维需要通过一个工具进行使用,flux
1.安装  yarn add flux
2.在src目录下 新建store目录,里面新建index.js
	-store有两个功能
	  -存放数据
	  -当数据发生改变时,视图要进行更新(当前组件中的state发生了改变,从新从store中获取数据,要想重新复制,那么要通过事件的发布,订阅)

store>index.js的内容

/* 
    store是Flux的一个组成部分
    功能
        1.存储状态
        2.更新视图 ->事件发布 - 订阅 -> Node的envents模块来实现
*/

const events = require('events')


//1.创建store模块
const store = {
    ...events.EventEmitter.prototype,//给store 添加属性 on emit  让store具有订阅和发布的功能
    state:{//定义一个状态
        count:0
    },
    getState(){//获取状态
        return this.state.count
    }
}

export  default store

//将store模块引入需要使用状态的文件(A.js),通过store.getState()这个方法给A.js里的状态赋值,
//然后进行数据展示

action_creators>index.js内容

/* 
    action
        用于将视图的逻辑迁移到flux的acttionCreators身上
        action都是方法,他的作用是创建action
*/

import { 
    INCREMENT, 
} from './actionType'
import dispatcher from '../dispatcher'


export const add = () => {
    //1.创建动作
    console.log('action')
    const action = {
        type:INCREMENT
    }
    //2.发送动作  action是不能发动的,得由dispatcher来发送
    dispatcher.dispatch( action )
}

dispatcher>index.js内容

/* 
    dispatcher
       作用: 修改数据
*/
import { Dispatcher } from 'flux'
import { INCREMENT } from '../actions_creators/actionType'
import store from '../store'
//1.得到dispatcher
const dispatcher = new Dispatcher()
//2.dispatcher要想使用得注册
//dispatcher.register(callback)
dispatcher.register((action) => {//actions中的动作
//判断是哪一个动作,对应的做数据修改
    switch (action.type) {
        case INCREMENT:
            console.log('dispatcher')
            store.state.count ++
            break;
    
        default:
            break;
    }
})

export default dispatcher

视图内容

import React,{ Fragment,useState,useEffect } from 'react'
import './index.scss'
import  store from '../../store'
import {
    add
} from '@/actions_creators'
class HotSale extends React.Component {
    constructor( props ){
        super(props)

        this.state = {
            count:store.getState() //1.视图初始化状态(从Flux得到状态)
        }

    }

    increment = () => {//2.视图进行相应的操作
        add()          //Flux的action_creators创建相应操作的动作,dispatcher发送动作,然后将相应的动作导入
        store.emit('addHandler')   //4.store.emit来发布订阅的事件来更新视图
    }

    componentDidMount(){           //3.通过store.on来订阅事件来准备更新视图
        store.on('addHandler',() => {
            this.setState({
                count:store.getState()
            })
        })
    }
    
    render(){
        return(
            <Fragment>
            <div className='hotsale-box'>
                 <button onClick = { this.increment }>+</button>
                 <p>count:{ this.state.count }</p>
             </div>
         </Fragment>
        )
    }
}

export default HotSale

在这里插入图片描述

redux

flux + 函数式编程 = redux
redux核心组成部分

  • store 数据管理者和存储者
  • actionCreators 动作创建者,发送动作给reducers
  • react Components 组件(视图层)
  • reducers 数据的修改者,返回一个新的 newstate 给 store

Redux的设计思想

  1. Web应用是一个状态机,视图于状态是一一对应的。
  2. 所有状态,保存在一个对象里(唯一数据源)
    注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,这学习react的时候,只是将react的组件作为redux中的视图层去使用

Redux的使用的三大原则:

  • SIngles Source of Truth(唯一数据源)
  • State is read-only(状态是只读的)
  • changes are made with pure function(数据的改变必须通过纯函数完成)

数据不分块

安装redux
	-yarn add redux
在src下面创建store文件夹,里面创建index.js

在这里插入图片描述
store>index.js

/* 
    数据的管理者和存储者
*/

import { createStore } from 'redux'
import rootReducer from '../reducers'	//在reducers里创建 rootReducer

const store = createStore( rootReducer )

export default store

reducers index.js

/* 
    reducer是一个纯函数
    接收两个参数 previousState  action
    previousState初始状态
    action是actions发送来的动作
*/
import {	//引入动作类型
    INCREMENT,
    ADDTODOS
} from '../actions/actionType'

const state = {//这是初始值  这个值只读,不能改
    count: 0,
    todos:[
        {
            id:1,
            task:'任务一'
        },
        {
            id:2,
            task:'任务二'
        }
    ]
}


const rootReducer = (previousState = state, action) => {
    /* state是只读的,不可变的,那么previousState也不能改 */
    //这里使用克隆   深浅都可以  深克隆最保险  深克隆使用  loadsh_.cloneDeep/Immutable.js来完成

    const newState = {//浅克隆
        ...previousState
    }

    //判断用户做了什么动作
    switch (action.type) {
        case INCREMENT:
            //用户操作->修改数据
            newState.count++
            break;
        case ADDTODOS:
            //用户操作->修改数据
            newState.todos.push({
                id:newState.todos.sort((a,b) => {
                    return b.id - a.id
                })[0].id+1,
                task:action.payload	//视图传递来的参数
            })
            
            break;
        default:
            break;
    }
    // console.log(newState)
    return newState //返回一个新的状态 store.getState可以拿到里面的数据
}


export default rootReducer

action>index.js

import { INCREMENT,ADDTODOS } from './actionType'
import store from '../store'

export const increnment = () => {

    // console.log('action')
    const action = {//创建动作
        type:INCREMENT
    }

    //发送动作
    store.dispatch(action)
}

export const addtodos = (val) => {//视图传递来的参数
    const action = {
        type:ADDTODOS,
        payload:val
    }
    
    store.dispatch(action)
}

上面操作过后需要更新视图
在所在组件的componentDidMount里 使用事件订阅 store.subscribe(()=>{ this.setState()})来更新视图

数据分块

1.技术栈
	1.redux
	2.react-redux 实现数据分块的
	3.redux 中间件
		-redux-thunk 数据请求
		-redux-saga 项目变大了  数据请求用这个  解决rdux-thunk数据请求异步回调问题
		-redux-promise

新建store文件夹对数据统一管理(唯一数据源),store>index.js 存储数据

import { createStore,applyMiddleware } from 'redux'//用来创建store的,thunk方这里面
import thunk from 'redux-thunk'         //用来数据请求的 得先有thunk才能做数据请求
import rootReducer from '../reducers'   

const store = createStore( rootReducer,applyMiddleware(thunk) ) 

export default store

action>index.js 请求数据
还需要创建动作类型文件

export const GET_MOVIES = 'GET_MOVIES' //创建 相应操作对应的动作类型

--------------------------------------------------------------------------
import request from '../utils/request'
import { GET_MOVIES } from './actionType'

export const getMovies = () => {//redux-thunk 要求稳返回值是一个函数,函数参数是dispatch
    
    return async dispatch => {
        
       const result = await request({
           method:'get',
           url:'/ajax/movieOnInfoList',
           params:{
            token: ''
           }
       }) 
      
       const action = {         //创建动作
           type:GET_MOVIES,     //动作类型  用户的操作对应相应的动作类型
           payload:result.data  //动作的结果
       }

       dispatch( action )       //发送动作
    }
}

reducers>index.js

import { combineReducers } from 'redux'
import homeReducer from './homeReducer'


const rootReducer = combineReducers({
    home:homeReducer                //将分块数据进行管理
})

export default rootReducer 

reducers>homeReducer(某一块数据)修改数据

import { GET_MOVIES } from '../actions/actionType'
const initState = {                 //定义初始化数据  
    data:null
}

const homeReducer = (state = initState,action) => {
    const newState = {              //因为数据只可读,所以浅拷贝一层,深拷贝保险但是 性能差  
        ...state
    }

    switch (action.type) {      //对应action里的动作 进行相应的操作
        case GET_MOVIES:
            newState.data = action.payload      //将action请求到的数据赋值给浅拷贝的数据
            break;
    
        default:
            break;
    }

    return newState                 //将浅拷贝的数据返回出去store就能拿到了
}

export default homeReducer

然后再index.js根目录文件里 用上下文包裹住根组件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { Provider } from 'react-redux'	//上下文组件
import store from './store'				//数据源

ReactDOM.render(
<Provider store = { store }>			//被包裹的组件的子组件都可以使用 connect组件
    <App />
</Provider>
, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

然后再相应的视图组件内使用容器组件

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'  
import { getMovies } from '../../actions'

/* 
    connect会根据UI组件自动生成一个容器组件,
    可以帮助我们获取store里面的数据和action里面的方法,
    然后通过属性自动绑定到UI组件身上,它还可以帮助我们更新视图
*/
 
class Home extends Component {

    componentDidMount(){
        this.props.getMovies()	//	这样就能拿到数据了
    }

    render() {
        return (
            <div>
                
            </div>
        )
    }
    
}

const mapStateFromProps = state => {
    return {
        data:state.home.data	//ui组件的props中就有data了
        
    }
}

const mapDispatchFromProps = dispatch => {
    return bindActionCreators({getMovies},dispatch)
}

export default connect (mapStateFromProps,mapDispatchFromProps)(Home)	//将action里的方法绑定到ui组件身上

/* 
    connect两个参数
        mapStateFromProps 将store里面的state转换成props,然后home组件继承容器组件的属性
        mapDispatchFromProps 将action里面的方法绑定在UI组件身上,以props的方式访问,然后帮我们发送action给redux
*/

Mobx

在这里插入图片描述

actions,事件调用,actions是唯一可以修改state的东西并且可能有其他副作用  **数据修改者**
state, 数据														  **数据存贮者**
component value 可以使用函数式组件从state中导出值 					  **数据更新的结果**
				mobx会自动更新并在它不再使用时将其优化   

reacts视图更新  														  **数据展示者**

使用mobx-react进行数据分块,使用mobx可以定义一个新的生命周期函数componentwillreact

  1. 创建项目-create-react-app app

  2. 进入项目 cd app

  3. 进行配置文件抽离-yarn eject

  4. 安装mobx - yarn add mobx mobx-react

    如果有git冲突
    我们要先将原文件放在本地暂存盘
    git add .
    git commit -m ''
    然后安装mobx mobx-react
     注意不要
    

    5.配置装饰器(修饰器es6)babel 解析装饰器

     yarn add babel-plugin-transform-decorators-legacy -D
     yarn add @babel/preset-env -D
     yarn add babel-plugin-transform-class-properties -D
     yarn add @babel/plugin-proposal-decorators -D
    

    6.配置peage.json

"babel": {
 "plugins": [
   [
     "@babel/plugin-proposal-decorators",
     {
       "legacy": true
     }
   ],
   "transform-class-properties"
 ],
 "presets": [
   "react-app",
   "@babel/preset-env"
 ]
 },


//注意: 以下两个配置顺序不可更改
//     [
//        "@babel/plugin-proposal-decorators",
//        {
//          "legacy": true
//        }
//      ],
//      "transform-class-properties"

在项目中的应用-分块

src 新建store目录=> index.js

用来打造store
导入下面打造的分片
import count from '分块路径'

const store = {
	//在store文件夹里打造分片的数据
	count

}

export default store

在store文件夹里打造分片的数据

import {
	observable,
	action
}
class Count {
	@observable //定义可观察的状态
	 num 0
	
	@action 	//定义用户交互的方法
	 increment(){
		this.props.store.count.num ++
	}
}

const count = new Count()

export default count

然后在index.js里从 'mobx-react’里导出 Provider

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { Provider } from 'mobx-react'	//上下文组件
import store from './store'				//数据源

ReactDOM.render(
<Provider store = { store }>			//被包裹的组件的子组件都可以使用 connect组件
    <App />
</Provider>
, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

在视图组件使用 inject

import React,{ Component } from 'react'

import { inject,observer } from 'mobx-react'

@inject('store')//inject也是一个函数,这个函数接收'store'作为参数,可以将store里的数据和方法给到组件身上

@observer

class Count extends Component {
	render(){
//通过inject注入store中的api,我们发现actions中的方法不会在this中显示,
	const { num,increment } = this.props.store.count
		return(
			<div>
				<button onClick = { increment.bind(this)  }> + <button>
				<p>count:{ num }</p>
			</div>
		)
	}
}

export default Count

mobx流程
在store.index中创建store,在store中存入分片,状态分片的内容为,定义的状态和改变状态的方法,通过上下文组件包裹根组件,在需要的视图组件里使用@inject(store),然后该组件的this.props。store.状态分片,就能访问到装和方法。注意!!!!方法是console不出来的,建议在方法中写一个console来判断是否已经拿到方法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值