Redux动作重用

时间:2015-11-27 03:09:07

标签: redux

我是react / redux的初学者。

我已经在我的应用中完成了基本组件<HeatMap />及其操作/减速器/存储,并且运行良好。

我将使用不同的设置(道具)渲染另一个<HeatMap />

我尝试做的是将这个2分量分开,因为当我dispatch更新action时,另一个同时执行。

问题1

我试过这个来分隔商店中的状态

import heatMap from './heat-map1'
import {combineReducers} from 'redux';

export let reducers = combineReducers({
    heatMap1: heatMap,
    heatMap2: heatMap
});

将RedReducers和connect两个热图组合在商店中的不同对象

export default connect((state)=> {
    return {
        onState: state.heatMap1.onState,
        config: state.heatMap1.config
    }
})(CHMSHeatMap1)

export default connect((state)=> {
    return {
        onState: state.heatMap2.onState,
        config: state.heatMap2.config
    }
})(CHMSHeatMap2)

这是正确的吗?

问题2

因为2个组件在调度动作时都会反应

我正在考虑分离共享行动,但我认为这不是一个好主意。或者问题可能不在这里。

那么你能告诉我这个问题的原因以及解决方法吗?

这是我的减速机

import * as actionTypes from '../actions/heat-map';
import Immutable from 'immutable';


const onState = {
    fetching: 'FETCHING',
    error: 'ERROR',
    drawn: 'DRAWN'
};

const initialState = {
    onState: onState.fetching,
    config: {}
};


export default function heatMapReducer(state = initialState, action) {
    let immutableState = Immutable.fromJS(state);
    switch (action.type) {
        case actionTypes.INITIALIZING:
            return immutableState.set('onState', onState.drawn).set('config', action.payload.initConfig).toJS();
        case actionTypes.FETCH_DATA_REQUEST:
            return immutableState.set('onState', onState.fetching).toJS();
        case actionTypes.FETCH_DATA_SUCCESS:
            return immutableState.set('onState', onState.drawn).setIn(['config','series',0,'data'],Immutable.fromJS(action.payload.mapData.data)).toJS();
        case actionTypes.FETCH_DATA_FAILURE:
            return immutableState.set('onState', onState.error).set('config', action.payload.mapData).toJS();
        default:
            return state;
    }
}

行动很简单

export function initializeConfig(initConfig) {
    return {
        type: INITIALIZING,
        payload: {
            text: 'Initializing',
            initConfig
        }
    }
}

export function requireMapData() {
    return {
        type: FETCH_DATA_REQUEST,
        payload: {
            text: 'Loading'
        }
    };
}
..........

//Async Action for fetching map data and redraw the map
export function fetchMapData(address) {
    return function (dispatch) {
        //dispatch requireMapData action to set the map in loading state
        dispatch(requireMapData());
        return fetch(address)
            .then(fetchUtil.checkHttpStatus) //check if 404
            .then(fetchUtil.parseJSON)
            .then(mapData => dispatch(fetchDataSucceed(mapData)))
            .catch(error => dispatch(fetchDataFailed(error)));
    }
}

谢谢你我的朋友。

3 个答案:

答案 0 :(得分:3)

您无法以您描绘的方式复制缩减器。两者都会以完全相同的方式对完全相同的行为做出回应。

解决方案是让所有热图数据处于相同的减速器状态。 e.g。

const initialState = {
    heatMap1: {},
    heatMap2: {}
};

export default heatmap(state = initialState, action) {
   // etc

现在,如果您想对两个热图使用相同的操作,则需要有一个操作属性,指定您要定位的堆映射。如果您有多张热图,我建议使用一系列热图,每个动作包含indexid,以定位特定的热图。 e.g。

function updateHeatMap(index, value) {
    return {
        type: UPDATE_HEATMAP,
        index: index,
        value: value
    }
}

答案 1 :(得分:2)

您还可以查看multireducer模块(https://github.com/erikras/multireducer)。它旨在完全解决您提出的方案。

所以你可以这样配置你的商店:

import multireducer from 'multireducer';
import heatMap from './heat-map1'
import {combineReducers} from 'redux';

export let reducers = combineReducers({
  multireducer: multireducer({
    heatMap1: heatMap,
    heatMap2: heatMap
  })
});

之后,您需要使用connectMultireducer()而不是redux的标准connect(),以便将商店的特定切片连接到特定组件,如下所示:

export default connectMultireducer((state)=> {
    return {
        onState: state.heatMap.onState,
        config: state.heatMap.config
    }
})(CHMSHeatMap)

最后,为了获得每个组件的状态的正确部分,您在传递它们时将传递给它:

<CHMSHeatMap multireducerKey="heatMap1"/>
<CHMSHeatMap multireducerKey="heatMap2"/>

显然,最好在multireducer回购中阅读实际的文档,但这应该给出一个简要的概述。基本上,该模块只是抽象了为通过multireducer函数创建的每个reducer添加基于键的查找的过程。

答案 2 :(得分:0)

我建议使用没有任何库的多减速器的原始概念。 基本思想是独特的Symbol动作类型和自包含的Redux模块,如下所示:

import * as services from './../../../api/services';

const initialState = {
  list: [],
};

function getListReducer(state, action) {
  return {
    ...state,
    list: action.payload.list,
  };
}

function removeItemReducer(state, action) {
  const { payload } = action;
  const list = state.list.filter((item, i) => i !== payload.index);
  return {
    ...state,
    list,
  };
}

export default class List {
  constructor() {
    // action types constants
    this.GET_LIST = Symbol('GET_LIST');
    this.REMOVE_ITEM = Symbol('REMOVE_ITEM');
  }
  getList = (serviceName) => {
    return async (dispatch) => {
      const list = await services[serviceName].get();
      dispatch({
        type: this.GET_LIST,
        payload: {
          list,
          serviceName,
        },
      });
    };
  }
  removeItem = (index) => {
    return (dispatch) => {
      dispatch({
        type: this.REMOVE_ITEM,
        payload: {
          index,
        },
      });
    };
  }
  reducer = (state = initialState, action) => {
    switch (action.type) {
      case this.GET_LIST:
        return getListReducer(state, action);

      case this.REMOVE_ITEM:
        return removeItemReducer(state, action);

      default:
        return state;
    }
  }
}

更多信息请参阅there