Source: reducers/componentsReducers.js

  1. /* eslint no-console: ["error", { allow: ["warn"] }] */
  2. /**
  3. * @module react-cmf/lib/reducers/componentsReducers
  4. */
  5. import get from 'lodash/get';
  6. import { Map, fromJS } from 'immutable';
  7. import invariant from 'invariant';
  8. import CONSTANTS from '../constant';
  9. export const defaultState = new Map();
  10. /**
  11. * given the state and action, determine if another component try to bind to a specific
  12. * component name space state and warn the user about this behaviour
  13. * @param {Object} state the CMF application state
  14. * @param {Object} action a redux action
  15. */
  16. export function warnIfAnotherComponentBind(state, action) {
  17. if (process.env.NODE_ENV !== 'production') {
  18. if (state.getIn([action.componentName, action.key])) {
  19. console.warn(`Beware component ${action.componentName} try to recreate an existing
  20. State namespace ${action.key}, meaning that the original one will be overloaded`);
  21. }
  22. }
  23. }
  24. /**
  25. * given the state and action, determine if a component at unmount try to delete
  26. * a state namespace that doesn't exist anymore and warn the user about this behavior
  27. * @param {Object} state the CMF application state
  28. * @param {Object} action a redux action
  29. */
  30. export function warnIfRemovingStateDoesntExist(state, action) {
  31. if (process.env.NODE_ENV !== 'production') {
  32. if (!state.getIn([action.componentName, action.key])) {
  33. console.warn(`Beware the component ${action.componentName} try to remove a non existing
  34. State namespace ${action.key}, it isn't a normal behavior execpt if two component are binded
  35. to this specific namespace`);
  36. }
  37. }
  38. }
  39. /**
  40. * given the state and action, determine if a component try to update a state namespace that
  41. * doesn't exist, throw an errror at dev time since such a behavior may lead to unintended bug
  42. * or runtime errors later on app execution.
  43. * @param {Object} state the CMF application state
  44. * @param {Object} action a redux action
  45. */
  46. export function errorIfMergingStateDoesntExist(state, action) {
  47. if (!state.getIn([action.componentName, action.key])) {
  48. invariant(
  49. process.env.NODE_ENV === 'production',
  50. `Error, the component ${action.componentName} try to mutate a non existing
  51. State namespace ${action.key}, this namespace may be not yet created or already removed.`,
  52. );
  53. }
  54. }
  55. /**
  56. * Reducer on charge to manage component remote state.
  57. * @param {object} state initial state
  58. * @param {object} action the executed action
  59. * @return {object} the new state
  60. */
  61. export function componentsReducers(state = defaultState, action) {
  62. switch (action.type) {
  63. case CONSTANTS.COMPONENT_ADD_STATE:
  64. warnIfAnotherComponentBind(state, action);
  65. if (action.initialComponentState) {
  66. return state.setIn(
  67. [action.componentName, action.key],
  68. fromJS(action.initialComponentState),
  69. );
  70. }
  71. return state.setIn([action.componentName, action.key], new Map());
  72. case CONSTANTS.COMPONENT_MERGE_STATE:
  73. errorIfMergingStateDoesntExist(state, action);
  74. return state.mergeIn([action.componentName, action.key], fromJS(action.componentState));
  75. case CONSTANTS.COMPONENT_REMOVE_STATE:
  76. warnIfRemovingStateDoesntExist(state, action);
  77. return state.deleteIn([action.componentName, action.key]);
  78. default: {
  79. const subAction = get(action, 'cmf.componentState');
  80. if (subAction) {
  81. return componentsReducers(state, subAction);
  82. }
  83. return state;
  84. }
  85. }
  86. }
  87. export default componentsReducers;