Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a ID back from a reducer in redux

I'm fairly new and trying to build a simple bookmark application with react & redux.

I can't spin my head around this problem:

A user can create one bookmark and add it to multiple folders. So I dispatch an addMark(bookmark) action, and after that addMark(folder) or editFolder(folder) if the folder already exists. As you can see, bookmark and folder are added via the same action, because in my state tree they are both just marks - distinguished by their type property.

My problem: How can I tell the folder-objects which is the new bookmark to add to folders list of bookmarks? How can I retrieve the ID of the newly created bookmark between the two dispatches?

Solutions I don't find satisfying:

  1. I know how the bookmark-ID is generated in the reducer (via Math.max over the existing bookmark IDs), so I can reproduce the new bookmark ID between the 2 dispatches.This sounds like a bad hack.
  2. Bookmarks and folders are kept in the same state-branch (same reducer), because they are both just "Marks", I could have a state-property that references the latest added bookmark, but this also sounds like a bad hack.

A little bit of source code, to understand what I have:

// mapping between dispatcher and props to my react view
const mapDispatchToProps = (dispatch) => ({
  saveMark: (mark) => {
    if (mark.id) {
      dispatch(editMark(mark));
    } else {
      dispatch(addMark(mark));
    }
  },
});
export default connect(mapStateToProps, mapDispatchToProps)(AddMark);

And Inside AddMark, which is the container component:

// save the bookmark first
this.props.saveMark({
      type: 'bookmark',
      title: this.state.title,
      url: this.state.url,
      icon: this.props.icon,
      style: this.state.style,
 });
 // now I need the bookmark ID
 folders.forEach(folder => {
    folder.children.push(bookmarkID) // <-- !!!
 });
 folders.forEach(folder => this.props.saveMark(folder));

I can't find a satisfying solution for this.

like image 567
goto.prototype Avatar asked Jun 06 '16 17:06

goto.prototype


People also ask

Can a reducer return value?

Reducers always have to return something even if it's null ; they should never return undefined . If a reducer's state is an object, you must always return a new object instead of editing the object in place. createStore() requires a single argument, which is the "root reducer" and returns a store .

What does a reducer return Redux?

In redux, Updation of state happens in the reducer function. Basically reducer function returns a new state by performing an action on the initial state.

Can we dispatch from reducer?

You are only disallowed to dispatch inside the reducers because they must have no side effects. If you want to cause a side effect in response to an action, the right place to do this is in the potentially async action creator.


1 Answers

I think that you should dispatch only one action here: addBookmark(), which accepts both bookmark object and folder.

Your code, which handles adding bookmark object into folder should be part of reducer.

Also, refer the Todos example in Redux project. It has id provided in action creation to make it possible to read it in the component. You can also use current state to compute latest id:

function addBookmark(bookmark, folder) {
   return (dispatch, getState) => {
       const newBookmark = Object.assign({
         id: Math.max(0, ...getState().bookmarks.map(b => b.id)) + 1,
       }, bookmark);
       dispatch({
         type: 'ADD_BOOKMARK',
         bookmark: newBookmark,
         folder: folder
       });
   }
}

Notice that example requires redux-thunk middleware to dispatch those actions.

Then you can get access to bookmark with id in the folders reducer

function folderReducer(state = [], action) {
  if(action.type === 'ADD_BOOKMARK') {
     return state.map(folder => {
       if(folder === action.folder) {
         return Object.assign({}, folder, {children: [...folder.children, action.bookmark.id]}
       }
       return folder;
     })
  }
  //another reducer code
  return state;
} 
like image 127
just-boris Avatar answered Oct 19 '22 17:10

just-boris