My Redux state stores a comments
object which stores an array of comments. Each comment
object has a replies
array in it. I am passing both the parent comment ID and the reply ID to my reducer with the intention to remove the reply from the replies array.
A simplified version of my top-level comments object looks like this:
{
"count": 4,
"data": [
{
id: 123,
text: 'This is a comment',
replies: [
{
id: 479,
text: 'This is a reply',
},
{
id: 293,
text: 'This is another reply',
},
],
},
{
id: 728,
text: 'This is another comment',
replies: [
{
id: 986,
text: 'This is a reply',
},
],
},
],
"pageSize": 5,
cursor: "",
}
And here is my reducer which appears to wrap the parent comment object in an array and flatten the replies (obviously not the desired result but I am at a loss as to the best way to tackle the nested array).
case types.DELETE_REPLY_SUCCESS: {
const content = Object.assign({}, state);
content.data = content.data.map((comment) => {
const newObj = { ...comment };
if (newObj.id === action.parentCommentId) {
return newObj.replies.filter(reply => reply.id !== action.replyId);
}
return newObj;
});
return content;
}
The answer above is more direct but I wanted to share some of my thoughts.
First off, this link on normalizing state in Redux solved what was a big problem for me...dealing with nested data structures...your code becomes very complex. 90% of your reducers should be surprisingly simple. And with nested data structures they become complex.
Although normalizer is a pretty standard tool for normalizing state i'd recommend writing your own at first. I learned a lot from doing it that way.
What is a normalized Data Structure?
It's flat. And it's typically relational.
Dan Abramov (who built Redux), suggests storing pieces of data grouped. So your comments become one group and your replies share another. Just like in a relational Database. Each "group" has its own "table".
At first this seemed counter intuitive to me because it feels like you are writing more data structure. You're not... and the payoffs are well worth it.
So you would store your data something like this
Why the big deal?
In what way does this make life easier? Well first off, if we ever want to display a list of comments, we can just
map()
through ourallIds
array and use the first parameter to access the key to get to the data.This means we can iterate through a single array instead of through a nested object.
In the same way, and in answer to your question you can delete an element by using
filter()
instead ofmap()
. I wont bother explaining filter here..it takes ten seconds to find examples that are better than anything I could explain.Then just make sure you've followed the standard Redux way of doing things.
Replicate your data structure using reducers. Your state should initialise with no data...that way you know you've done it right.
Write your reducers that handle it's specific piece of state (comments reducer, etc) For me, these normally consist of switch statements that either return state or return a new state.
Write actions that supply a reducer the new data it needs. Always follow the JS principle of having a function handle one job. Actions shouldn't do multiple things.
NOTE however using middleware like thunk, actions can dispatch other actions which can result in logic awesomeness!
a delete action for a comment might look something as simple as
This gives us all we need. By using the previously mentioned switch statement in our reducer, we can check to see what
type
of action is being dispatched. (this tells us what to do with the supplied data) and which element to delete i.e the payload.You can follow this simple approach for 85% of your app needs.
I understand there's a lot more to Redux than this but this approach really helped me get to grips with how to view Redux and how to manage and manipulate state. I HIGHLY recommend going through the whole eggheads.io tutorial by Dan Abramov linked above. He does a really great job of explaining pretty much everything in detail.
I hope this long answer to your short question helps.
Updating a nested structure can be very nasty in redux. I suggest using a flatter structure. You can do this using normalizer or manually.
However, if you need to update your existing structure, these are the steps:
Example