Reputation: 1091
I have an API response which has a lot of nested entities. I use normalizr to keep the redux state as flat as possible.
For eg. the api response looks like below:
{
"id": 1,
"docs": [
{
"id": 1,
"name": "IMG_0289.JPG"
},
{
"id": 2,
"name": "IMG_0223.JPG"
}
],
"tags": [
{
"id": "1",
"name": "tag1"
},
{
"id": "2",
"name": "tag2"
}
]
}
This response is normalized using normalizr
using the schema given below:
const OpeningSchema = new schema.Entity('openings', {
tags: [new schema.Entity('tags')],
docs: [new schema.Entity('docs')]
});
and below is how it looks then:
{
result: "1",
entities: {
"openings": {
"1": {
"id": 1,
"docs": [1,2],
"tags": [1,2]
}
},
"docs": {
"1": {
id: "1",
"name": "IMG_0289.JPG"
},
"2": {
id: "2",
"name": "IMG_0223.JPG"
}
},
"tags": {
"1": {
"id": 1,
"name": "tag1"
},
"2": {
"id": 2,
"name": "tag2"
}
}
}
}
The redux state now looks something like below:
state = {
"opening" : {
id: 1,
tags: [1,2],
docs: [1,2]
},
"tags": [
{
"id":1,
"name": "tag1"
},
{
"id":2,
"name": "tag2"
}
],
"docs": [
{
"id":1,
"name": "IMG_0289.JPG"
},
{
"id":2,
"name": "IMG_0223.JPG"
}
]
}
Now if I dispatch an action to add a tag
, then it adds a tag
object to state.tags
but it doesn't update state.opening.tags
array. Same behavior while deleting a tag also.
I keep opening
, tags
and docs
in three different reducers.
This is an inconsistency in the state. I can think of the following ways to keep the state consistent:
tags
reducer and opening
reducer and update tags subsequently at both places.What is the right way to do this. Shouldn't the entities be observing for changes to the related entities and make the changes itself. Or there are any other patterns that could be followed any such action.
Upvotes: 5
Views: 3236
Reputation: 509
First to summarise how normalizr
works: normalizr
flattens nested API response to entities defined by your schemas. So, when you made your initial GET openings
API request, normalizr flattened the response and created your Redux entities
and the flattened objects: openings
, docs
, tags
.
Your suggestions are viable, but I find normalizr
's real benefit in separating API data from UI state; so I don't update the data in Redux store myself... All my API data are kept in entities
and they are not altered by me; they are vanilla back-end data... All I do is to do a GET
upon state changing API operations, and normalise the GET
response. There is a small exception for DELETE
case that I'll expand on later on... A middleware will deal with such cases, so you should use one if you haven't been using. I created my own middleware, but I know redux-promise-middleware is quite popular.
In your data set above; when you add a new tag
, I assume you are making an API POST
to do so, which in turn updates the back-end. Then, you should do another GET openings
which will update the entities
for openings and all its nested schemas.
When you delete a tag
, e.g. tag[2], upon sending the DELETE
request to the back-end, you should nullify the deleted object in your entities state, ie. entities.tags[2] = null
before making the GET openings
again to update your normalizr entities.
Upvotes: 5