重用 redux reducer 和 action
reuse redux reducers and actions
假设我有一个节缩减器来保存节的数据
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"))
时,我都会在两个状态树上得到 sectionBData
sectionA
和 sectionB
。即使 sectionA
第一次被调度,sectionB
已经填充了 sectionA
数据,即使它还没有被调度。
在这种情况下重用 reducer 和 action 的正确方法是什么?还是我必须为每个部分创建 action 和 reducer,即使它们是相同的?
=======更新=====
减速器
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
的操作时,它会用收到的数据替换整个状态...因此状态中可能只有一个部分和数据。 ,这显然是你不想要的。
你可以做的是,在你的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,
});
假设我有一个节缩减器来保存节的数据
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"))
时,我都会在两个状态树上得到 sectionBData
sectionA
和 sectionB
。即使 sectionA
第一次被调度,sectionB
已经填充了 sectionA
数据,即使它还没有被调度。
在这种情况下重用 reducer 和 action 的正确方法是什么?还是我必须为每个部分创建 action 和 reducer,即使它们是相同的?
=======更新=====
减速器
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
的操作时,它会用收到的数据替换整个状态...因此状态中可能只有一个部分和数据。 ,这显然是你不想要的。
你可以做的是,在你的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,
});