简体   繁体   中英

Access the state in an action in redux

Many links and tutorials advice to group the logic in action creators in order to simplify the reducer logic.

Imagine a simple (normalized) state:

const initialState = {
  parent: {
    allIds: [0],
    byId: {
      0: {
        parentProperty: `I'm the parent`,
        children: [1, 2]
      }
    }
  },
  children: {
    allIds: [1, 2],
    byId: {
      1: {
        childrenProperty: `I'm the children`
      },
      2: {
        childrenProperty: `I'm the children`
      }
    }
  }
}

I would now delete the parent. Since only the parent refers to the children, I would also delete the children too.

I imagine a action creator like this:

function deleteParents(parentId) {
  return {type: 'DELETE_PARENT', payload: {parentId}};
}

and

function deleteChild(childId) {
   return {type: 'DELETE_CHILD', payload: {childId}};
}

For now, to manage this case I do something like this (with redux-thunk)

function deleteParentAndChildren(parentId) {
  return (dispatch, getState) {
    const childrenIds = myChildrenSelector(getState(), parentId);
    const deleteChildrenActions = childrenIds.map(deleteChild);
    const deleteParentAndChildrenAction = batchActions([
      deleteParents(parentId),
      ...deleteChildrenActions
    ], 'DELETE_PARENT_AND_CHILDREN');
    dispatch(deleteParentAndChildrenAction);
  }
}

In that way, I compose little action into big one, and the reducer logic is very simple because it only consist to delete a key in an object.

Conversely, I don't like to use redux-thunk (used to async actions) just to get the state (and this is considered as anti pattern).

How do you guys manage this type of problems ? Does a tool like redux-sage may help ?

您似乎遇到的问题似乎相当普遍,如果您的应用程序有些复杂,我建议您使用redux-orm ,虽然有点难以理解,然后再进行集成,但是一旦设置,它就可以抽象出您实体之间所有艰苦的工作。

I opine differently here. The way I would do it is, I would delete child while deleting parent but not y dispatching child_delete action. When you create new state while deleting parent in reducer, at that time, you can access the children referred by that parent, and remove those as well from state.

Also, if you still want to dispatch actions separately, you can pass childids from component to action. From that action, you can dispatch two different actions, deleting parent and chilren ids.

----------- EDIT -------

// The initial application state
const initialState = {
  parent: {
    allIds: [0],
    byId: {
      0: {
        parentProperty: `I'm the parent`,
        children: [1, 2]
      }
    }
  },
  children: {
    allIds: [1, 2],
    byId: {
      1: {
        childrenProperty: `I'm the children`
      },
      2: {
        childrenProperty: `I'm the children`
      }
    }
  }
}

export default function batchManagement(state = initialState, action) {
  switch (action.type) {
    case 'DELETE_PARENT':  //assuming action.deleteParents = [0]
      //Here you have access to state, so you can change parents and children as well, and create a totally new state
    case 'DELETE_CHILDREN':
      //Return a new object for state
    default:
      return state;
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM