Redux概念

2022-03-19  本文已影响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使用流程
具体使用流程,以todolist为例
// 第一步: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的拆分
// 先在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
// 在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的设计使用原则

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;
总结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合并成大的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
    };
}
import headerReducer from '../common/header/store/reducer';
上一篇下一篇

猜你喜欢

热点阅读