Redux 动作重用
Redux action reuse
我是 react / redux 的初学者。
我已经在我的应用程序中完成了一个基本组件 <HeatMap />
,它的操作/reducer/store 运行良好。
我将渲染另一个 <HeatMap />
具有不同的设置(道具)。
我想要做的是将这 2 个组件分开,因为当我 dispatch
一个更新 action
在一个中,另一个同时执行它。
问题 1
我试过这个来分隔商店中的状态
import heatMap from './heat-map1'
import {combineReducers} from 'redux';
export let reducers = combineReducers({
heatMap1: heatMap,
heatMap2: heatMap
});
combineReducers 和 connect
存储中不同对象中的 2 个热图
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)));
}
}
谢谢你我的朋友。
您不能按照您描述的方式复制减速器。两者将以完全相同的方式对完全相同的动作做出响应。
解决方案是让所有热图数据都处于相同的 reducer 状态。例如
const initialState = {
heatMap1: {},
heatMap2: {}
};
export default heatmap(state = initialState, action) {
// etc
现在,如果您想对两个热图使用相同的操作,您将需要一个操作 属性 指定您要定位的堆图。如果您有多个热图,我会推荐一个热图数组,每个操作都包含一个 index
或 id
以针对特定的热图。例如
function updateHeatMap(index, value) {
return {
type: UPDATE_HEATMAP,
index: index,
value: value
}
}
您还可以查看 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 添加基于键的查找的过程。
我建议在没有任何库的情况下使用 multireducer 的原始概念。
基本思想是独特的 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。
我是 react / redux 的初学者。
我已经在我的应用程序中完成了一个基本组件 <HeatMap />
,它的操作/reducer/store 运行良好。
我将渲染另一个 <HeatMap />
具有不同的设置(道具)。
我想要做的是将这 2 个组件分开,因为当我 dispatch
一个更新 action
在一个中,另一个同时执行它。
问题 1
我试过这个来分隔商店中的状态
import heatMap from './heat-map1'
import {combineReducers} from 'redux';
export let reducers = combineReducers({
heatMap1: heatMap,
heatMap2: heatMap
});
combineReducers 和 connect
存储中不同对象中的 2 个热图
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)));
}
}
谢谢你我的朋友。
您不能按照您描述的方式复制减速器。两者将以完全相同的方式对完全相同的动作做出响应。
解决方案是让所有热图数据都处于相同的 reducer 状态。例如
const initialState = {
heatMap1: {},
heatMap2: {}
};
export default heatmap(state = initialState, action) {
// etc
现在,如果您想对两个热图使用相同的操作,您将需要一个操作 属性 指定您要定位的堆图。如果您有多个热图,我会推荐一个热图数组,每个操作都包含一个 index
或 id
以针对特定的热图。例如
function updateHeatMap(index, value) {
return {
type: UPDATE_HEATMAP,
index: index,
value: value
}
}
您还可以查看 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 添加基于键的查找的过程。
我建议在没有任何库的情况下使用 multireducer 的原始概念。
基本思想是独特的 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。