重用 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 sectionAsectionB。即使 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,
});