React redux normalizr: how to deal with nested objects?

Let's say I have a structure that is the result of one fetch from the API and using "normalizr" for my entities:

entities: { users:{ 1: { name: 'John', posts: [ 1, 4 ] } }, posts: { 1: { name: 'First Post', }, 4: { name: 'Second Post', } } } 

Now I have a method that filters user messages, which will basically do this:

 let filteredPosts = {}; entities.users.posts.forEach(key => { if(posts.hasOwnProperty(key)) filteredPosts[key] = posts[key] }); 

And the page on which messages from this user are displayed, for example:

 render() { return( <div> {Object.keys(filteredPosts).map(key => { return ( <div>{filteredPosts[key].name}</div> ); })} </div> ) } 

My essential reducer is very simple:

 import { merge } from 'lodash'; ... function entities(state = { users: {}, posts: {} }, action) { if (action.response && action.response.entities) { return merge({}, state, action.response.entities); } return state; } 

Now, if I make an API request to add a message for this user, returning a newly created record record, this record will be automatically added to messages on my entities.

How will I update the user to reflect this change so that the user now has 3 posts with a new post identifier in the array?

Should I create a reducer and listen to the create message action and update state.entities.users.posts there? Reinstalling objects is not an option. What would be the best way to do this?

thanks

UPDATE:

This is a solution that I must use right now to keep the data consistent. I am changing my account response for the generated message id. Iknow This can be decomposed into several reducers, but I'm still wondering if there is a more direct and more direct approach, when I do not need to do this for each nested object.

 function entities(state = {}, action) { ... if(action.type === 'POST_ADD_SUCCESS') { // Get the user id from the created post let userId = response.entities.posts[response.result].userId; // Add the user with all his posts to the response response.entities.users = { [userId]: { posts: [...state.users[userId].posts, response.result] } } } ... // Merge normally return merge({}, state, response.entities); } 
+5
source share
3 answers

Your updated snippet looks mostly along the right path, although I'm not sure why you are still referencing the “answer” there. Your action creation function should probably capture the user id and mail id, and when the AJAX call succeeds, create an action that looks like {type : POST_ADD_SUCCESS, userId : userId : postId} . In other words, the reducer does not need to know anything about the “response”, just to add the message identifier “x” to the list for user identifier “y”.

+1
source

Why not just use normalizr as middleware instead of skating on your own? Something like https://github.com/wbinnssmith/redux-normalizr-middleware

0
source

Have you considered sending a new action with formatted objects to successful messages in the API?

 const foo = (entities) => { type: "POST_ADD_SUCCESS" response : { entities } } 

The type of action does not matter, since the reducers of your objects will intercept the action anyway

0
source

Source: https://habr.com/ru/post/1241846/


All Articles