Reputation: 63
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:
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.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.
Upvotes: 6
Views: 4618
Reputation: 9746
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;
}
Upvotes: 3
Reputation: 6276
Reducers are just manipulating your store's instance. You may the current snapshot of your state using getState()
Upvotes: 0