美文网首页
Redux概念

Redux概念

作者: 泡杯感冒灵 | 来源:发表于2022-03-19 15:12 被阅读0次
React本身是一个轻量级的视图框架,如果只用react框架,做大型项目的时候,组件间的传值将会变得非常麻烦。这个时候,我们需要用引入数据管理框架Redux, Redux就是把组件中的数据,放到一个公用的存储区域去存储,然后当一个组件改变store里的数据的时候,其他组件会感知到store里数据的变化,然后重新去取store里的最新数据。Redux大大简化了数据的传递难度。
image.png
Redux = Reducer + Flux
Redux的工作流程

简单理解为以下流程:组件(React Components)告诉Store,我需要获取你里边的数据(Action Creators),但是到底该给组件什么数据呢?Store并不知道, 这个需要Reducers告诉Store应该给什么数据,Store知道了以后,把数据给组件就可以了。
同样道理,当组件要修改Store里的数据的时候,需要先告诉Store,我要改变你里边的数据(Action Creators),但是Store不知道怎么去帮你改变里边的数据,它需要去问 Reducers,Reducers会告诉Store该怎么去修改数据,当Store改好数据以后,会通知组件,数据已经修改好了,你可以重新来获取数据了。这样组件就可以重新获取最新的数据了!

image.png
redux使用流程
  • 安装redux npm install --save redux
  • 创建一个store,具体方法是,src下,创建一个store文件夹,里边创建一个index.js文件,然后index.js里边引入redux里的 createStore方法,当然我们不能单单创建一个store,还需要在创建store的时候,传入一个reducer,reducer返回的必须是一个函数,这个函数接收两个参数,state和action,reducer负责管理整个应用里的一些数据,怎么处理,怎么存。
    image.png
    image.png
    第一次reducer第一次执行的时候,store传的state是没有数据的,所以准备了一个defaultState作为默认值,复制给state,然后再把这个state返回给store,所以defaultState实际上,就是store的默认值。
具体使用流程,以todolist为例
  • 首先我们要实现input框输入的时候,store里的inputValue值跟着改变的功能。然后把store里的inputValue值放入store的list.
// 第一步:input框上,要监听input的change事件,并绑定事件处理函数。
     <Input 
          value={this.state.inputValue}  
          placeholder="todo info" 
          style={{width:'300px',marginRight:'10px'}}
          onChange={this.handleInputChange}
     >
     </Input>

// 第二步:当change事件触发的时候,创建一个action,action是一个对象。
// action包含type,要做什么事(自定义名字),和要传的数据。
// 然后再调用store的dispatch方法,把这个action传给store
    handleInputChange(e){
        const action = {
            type:'change_input_value',
            value:e.target.value
        }
        store.dispatch(action);
    }

// 第三步:store本身是不对数据进行处理的,接收到组件传的action后,会把当前store里的内容和这个action,一起给到reducer。
// reducer就能接受到store之前的内容(state)和传过来的action
// reducer根据action的类型,对数据进行处理,然后把新的数据return出去,返回给store
export default (state = defaultState, action) => {
    if(action.type === 'change_input_value'){
        // 注意 reducer可以接收state,但是决不能修改state,所以下边要对state进行深拷贝
        const newState = JSON.parse(JSON.stringify(state));
        newState.inputValue = action.value;
        return newState;
    }
    if(action.type === 'add_todo_item'){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.push(newState.inputValue);
        newState.inputValue = '';
        console.log(newState);
        return newState;
    }
    return state;
}

// 第四步 store拿到最新的state之后,把之前的state替换掉

// 第五步 组件通过store.subscribe方法监听store的变化,并触发绑定的函数
// 在subscribe绑定过函数里,重新获取store里的最新的数据,并修改自己的state
    constructor(props){
        super(props);
        this.state = store.getState();
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleStoreChange = this.handleStoreChange.bind(this);
        this.handleBtnClick = this.handleBtnClick.bind(this);
        store.subscribe(this.handleStoreChange);
    }
    handleStoreChange(){
        this.setState(store.getState());
    }

注意 reducer可以接收state,但是决不能修改state,所以要对state进行深拷贝

ActionTypes的拆分
  • 当我们创建action的时候,会定义这个action的type,值是自定义的字符串,但是这里有个问题,当我们使用这个字符串进行action的判断的时候,如果字符串写错了,页面是不会报错的,不利于我们定位问题。这个时候,我们可以对action的type进行拆分,使用常量代替原来的字符串。
// 先在store下创建 actionTypes文件,里边定义types的常量并导出
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';


// 在用到action的type的地方,引入刚才定义的常量
import {CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM} from './store/actionTypes';

// 使用的时候,直接用常量代替字符串
    handleBtnClick(e){
        const action = {
            type:ADD_TODO_ITEM
        }
        store.dispatch(action);
    }
  • 然后我们在使用过程中,如果不小心写错了变量某个字符,页面就会报错。
使用actionCreators 统一创建 action
  • 比较简单功能,action分散在业务逻辑里边还可以,但是当业务逻辑非常复杂的情况下,action到处都是,对后期的测试和管理是非常不方便的。所以,我们要把action拆分到actionCreator 里进行统一的创建管理。
// 在store下创建actionCreators.js文件,我们把action的创建统一放到这个文件里,对action进行统一的管理,
// 主要是为了提高代码的可维护性,方便自动化测试
import {CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM} from './actionTypes';

// 定义一个常量,是一个函数,该函数返回一个对象,对象包含action的type和值
export  const getInputChangeAction = (value) => ({
    type: CHANGE_INPUT_VALUE,
    value
})

export  const getAddItemAction = () => ({
    type: ADD_TODO_ITEM
})

export  const getDeleteItemAction = (index) => ({
    type: DELETE_TODO_ITEM,
    index
})

// 具体的使用,先引入这些actionCreators 里的action
import {getInputChangeAction, getAddItemAction,getDeleteItemAction} from './store/actionCreators';

// 然后使用store.dispatch去触发action
    handleInputChange(e){
        const action = getInputChangeAction(e.target.value);
        store.dispatch(action);
    }
    handleStoreChange(){
        this.setState(store.getState());
    }
    handleBtnClick(e){
        const action = getAddItemAction();
        store.dispatch(action);
    }
    handleItemDelete(index){
        const action = getDeleteItemAction(index);
        store.dispatch(action);
    }

注意Redux的设计使用原则

  • 注意Redux的设计使用原则,第一个就是store必须是唯一的,也就是整个应用中只有一个store作为公用存储
  • 只有store能够改变自己的内容。(reducer返回了数据,store会用这个数据自己去替换自己原来的数据),换句话说这也是为什么reducer不能修改state的内容,state指的就是store里的数据
  • Reducer必须是纯函数(纯函数指的是,给定固定的输入,就一定会有固定的输出,而且不会有任何的副作用)。如果函数里有ajax请求,setTimeout等异步的时候或与日期相关的时候,就不是固定的输入了,所以Reducer里不能有异步的操作,也不能有跟时间相关的操作
export default (state = defaultState, action) => {
    if(action.type === CHANGE_INPUT_VALUE){
        const newState = JSON.parse(JSON.stringify(state));
        // 如果inputValue = new Date().那么就不会是一个固定的值了。是不行的。
        newState.inputValue = action.value;
        // 如果把newState 换成state,那么就是改变了参数,而对reducer传入的参数的修改是有副作用的。
        state.inputValue = action.value;
        return newState;
    }
    if(action.type === ADD_TODO_ITEM){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.push(newState.inputValue);
        newState.inputValue = '';
        return newState;
    }
    if(action.type === DELETE_TODO_ITEM){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.splice(action.index,1);
        return newState;
    }
    
    return state;
}
Redux-DevTools 是一个非常棒的工具,它可以让你实时的监控Redux的状态树的Store,在谷歌扩展程序安装后,要想开发环境下使用,还需配置。
// 未配置之前,创建的store
import { createStore} from "redux";
import reducer from './reducer';

const store = createStore(reducer);
export default store;

// 配置以后,创建是store
import { createStore,applyMiddleware, compose } from "redux";
import reducer from './reducer';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, /* preloadedState, */ composeEnhancers());
export default store;
  • 当这个图标变绿色就证明配置成了,可以调试了


    image.png
总结Redux的核心API
  1. createStore 绑我们创建store
  2. store.dispatch方法,帮我们派发创建的action,这个action会传递给store
  3. store.getState方法,帮我们获取到store里的所有的数据内容
  4. store.subscribe方法,帮我们订阅store里数据的改变,只要store发生改变,subscribe方法接收的函数,就会被执行。
如果说store是图书管理员,那么reducer就可以看作是图书记录手册,管理员需要通过记录手册来对数据进行操作。随着项目复杂度的增加,如果reduce存放过多的数据,可能造成代码的低可维护性,这个时候,我们就需要把一个reducer拆分成多个子的reducer,最后再做整合。具体怎么做呢?
  • 首先,创建子的reducer,比如我的Header文件夹里存放的都是Header组件的内容,那么这个时候,可以在Header文件夹下创建一个store文件夹,store文件夹下再创建一个reducer.js文件。

  • 然后在总的store文件夹下的reducer.js文件里,通过combineReducers方法进行整合。

// 把一些小的reducer合并成大的reducer
import { combineReducers } from 'redux';
import headerReducer from '../common/header/store/reducer';

export default combineReducers({
    // header是自定义的名字,可随意起名
    header:headerReducer
})
image.png
  • 整合以后,我们再取值的时候,就需要多一层。
// 没用拆分之前
const mapStateToProps = (state) => {
    return {
        focused:state.focused
    };
}

// 拆分后
const mapStateToProps = (state) => {
    return {
        focused:state.header.focused
    };
}
  • 当然了,像上边那样创建子reducer,在总的reducer引入子reducer的时候,层级有可能会很深。
import headerReducer from '../common/header/store/reducer';
  • 这个时候,可以给子reducer创建一个出口文件,index.js,然后在出口文件里,把recucer导出


    image.png
  • 然后在总的reducer里引入的时候,就可以这样


    image.png

相关文章

  • Redux简介

    Redux React-redux React-router Redux 1、基本用法: Redux中存在几个概念...

  • redux基础

    Redux react-redux React-router Redux 1、基本用法: Redux中存在几个概念...

  • redux 总结

    redux redux概念 Redux是JavaScript应用程序的可预测状态容器。 redux 设计思想 We...

  • redux 系列

    redux 中文手册 核心概念 redux-saga 中文手册 react-redux 入坑指南

  • Redux概念图

    Redux概念图

  • Redux概念

    React本身是一个轻量级的视图框架,如果只用react框架,做大型项目的时候,组件间的传值将会变得非常麻烦。这个...

  • redux学习笔记

    什么是redux架构 //首先我们应该认识redux的核心store,store直译过来就是仓库,redux概念中...

  • redux-thunk以及自定义redux中间件

      前面几篇文章详细介绍了mini-redux、mini-react-redux,其中还有一个概念,便是redux...

  • Redux使用心得

    一、前言 二、 Redux的设计思想 三、 Redux的三原则 三、 Redux的基本概念 3.1 store 例...

  • 【学习笔记 】React ⑥ Redux工作流

    Redux基础概念     在了解Redux之前首先思考一个问题:为什么要使用Redux?    React是一个...

网友评论

      本文标题:Redux概念

      本文链接:https://www.haomeiwen.com/subject/npnvdrtx.html