假设我有一个section reducer来保存section的数据
const initialState = {
data: [],
section: ''
};
const sectionReducer = function(state = initialState, action) {
switch(action.type) {
case types.IMPORT_DATA_SUCCESS:
return Object.assign(
{},
state,
{
section: action.section,
data: action.data
}
);
}
return state;
}
并且我需要具有相同数据结构和动作的几个节。那我该怎么做呢
import { combineReducers } from 'redux';
import sectionReducer from './sectionReducer';
const reducers = combineReducers({
sectionA: sectionReducer,
sectionB: sectionReducer
});
export default reducers;
操作就像
一样简单import sectionAData from '../data/sectionAData';
...
export const importDataSuccess = (section, data) => {
return {
type: types.IMPORT_DATA_SUCCESS,
section: section,
data
}
}
export const loadData = (section) => {
const dataSet = (() => {
switch(section) {
case "SECTIONA":
return sectionAData
break;
case "SECTIONB":
return sectionBData
break;
}
})()
return (dispatch) => {
dispatch(importDataSuccess(section, dataSet))
}
}
上述方法的问题是每次我调用componentA
上的this.props.dispatch(loadData("SECTIONA"))
和componentB
上的this.props.dispatch(loadData("SECTIONB"))
时,我在状态树sectionA
和sectionB
上都得到sectionBData
。即使sectionA
第一次被调度,sectionB
已经被sectionA
数据填充,即使它还没有被调度。
在这种情况下重用减速器和动作的正确方法是什么?或者我必须为每个部分创建action和reducer,即使它们是相同的?
======= UPDATE =====
齿轮const initialState = {
data: []
};
const sectionReducer = function(state = initialState, action) {
switch(action.type) {
case types.IMPORT_DATA:
if ( action.section ) {
return state.data.push({ section: action.section, data: action.data });
}
break;
}
return state;
}
...
const reducers = combineReducers({
sections: sectionReducer
});
export default reducers;
行动export const importData= (section, data) => {
return {
type: types.IMPORT_DATA,
section,
data
}
}
export const loadData = (section) => {
const dataSet = (() => {
switch(section) {
case "SECTIONA":
return sectionAData
break;
case "SECTIONB":
return sectionBData
break;
}
})()
return (dispatch) => {
dispatch(importData(section, dataSet))
}
}
组件
class SectionWrapper extends Component {
componentDidMount() {
this.props.dispatch(loadData(this.props.const))
}
render() {
return (
<div>
<Section
title={this.props.title}
id={this.props.id}
data={this.props.data} />
</div>
)
}
}
const mapStateToProps = function(store, ownProps) {
const section = store.sections.find( (item) => { return item.section === ownProps.const; })
const data = section.data
return {
data
};
}
SectionWrapper.propTypes = {
title: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
const: PropTypes.string.isRequired
}
export default connect(mapStateToProps)(SectionWrapper);
存储const createStoreWithMiddleware = compose(
applyMiddleware(
thunkMiddleware,
createLogger()
),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
const store = createStore(
reducers,
createStoreWithMiddleware
);
export default store;
现在,当sectionReducer
接收到类型为IMPORT_DATA_SUCCESS
的动作时,它将整个状态替换为接收到的数据…所以状态中可能只有一个section和数据。,这显然是你不想要的。
你可以做的是,在你的sectionReducer
const initialState = {
data: [],
};
const sectionReducer = function(state = initialState, action) {
switch(action.type) {
case types.IMPORT_DATA_SUCCESS:
// action contains { type, section, data }
// added if statement to make sure data is not empty.
if ( action.section && action.data ) {
state.data.push({ section: action.section, data: action.data });
return Object.assign( {}, state );
}
return state;
case types.UPDATE_IMPORTED_DATA:
// action contains { section, data }
let index = state.data.findIndex( item => { return item.section === action.section; });
state.data[index] = { section: action.section, data: action.data }
return state;
default:
return state;
}
}
使用这种方法,您可以存储n
数量的区段,也可以很容易地更新它们。
当你想访问特定部分的数据时,你可以执行
let findSectionByName = ( sections, section_name ) => {
return sections.find( (item) => { return item.section === section_name; })
}
let section = findSectionByName( state.sections, 'SECTIONA' );
您还必须更改
const reducers = combineReducers({
sectionA: sectionReducer,
sectionB: sectionReducer
});
const reducers = combineReducers({
sections: sectionReducer,
});