Bogdan Slovyagin
Bogdan Slovyagin

Reputation: 1139

How to normalize an array of objects in the flattest way for the Redux?

Beware! The question may be confusing and not relevant because my assumptions about the cause of the bug were wrong, the problem was in reducer, not in a way I represented a data.

So, the correct answer for the question is jpdelatorre’s one, but Joao’s is about the bug itself.

Let’s say I have JSON response from server which is an array of nested objects. How to flatten it out making store handling as easy as possible? I’ve tried to use a normalizr tool like this:

const imageSchema = new Schema('image', { idAttribute: 'id' });
const tooltipSchema = new Schema('tooltips', { idAttribute: 'id' });
imageSchema.define({
    tooltips: arrayOf(tooltipSchema),
});
const initData = data.map(item => normalize(item, imageSchema));

But I believe I’m doing it wrong because it doesn’t help much. The store is still too complex and therefore I need to use some recursive stuff in reducer to update the state.

Moreover, a deeply nested state makes working with react-redux connect() very hard too, because it does only a shallow comparison.

The shape of the response is like:

[
  {
    "id": 1,
    "title": "Partridge",
    "tooltips": [
      {
        "id": 10,
        "x": 0.56,
        "y": 0.59,
        "content": "Jacky"
      },
      {
        "id": 11,
        "x": 0.08,
        "y": 0.8,
        "content": "Sarah"
      }
    ]
  },
  {
    "id": 2,
    "title": "The Great Seal of South Australia",
    "tooltips": [
      {
        "id": 20,
        "x": 0.77,
        "y": 0.74,
        "content": "A sheaf of wheat"
      },
      {
        "id": 21,
        "x": 0.16,
        "y": 0.2,
        "content": "A sheep"
      }
    ]
  }
]

Upvotes: 1

Views: 6414

Answers (2)

jpdelatorre
jpdelatorre

Reputation: 3593

Try this with normalizr

const imgSchema = new Schema('image', { idAttribute: 'id'});
const tooltipSchema = new Schema('tooltip');
imgSchema.define({
   tooltips: arrayOf(tooltipSchema)
});

const normalizedData = normalize(data, arrayOf(imgSchema));
console.log(normalizedData);

This will give you an output of

{
   entities: {
      image: {
         1: {
            id: 1,
            title: 'Partride',
            tooltips: [10, 11]
         },
         2: {
            id: 2,
            title: 'The Great Seal...',
            tooltips: [20, 21]
         }
      },
      tooltips: {
          10: {
              id: 10,
              content: 'Jacky',
              x: 0.56,
              y: 0.59
          },
          ...
      }
   },
   result: [1, 2]
}

You can then save it to your redux store.

Your question is How to normalize an array of objects in the flattest way for the Redux?. I believe this is how to do it.

Upvotes: 4

Joao
Joao

Reputation: 2746

Based on your sample here, It seems like you're trying to modify the state (hence the reason you're having trouble because of redux's shallow comparison). State should be regarded as immutable and everything returned in your reducers should be completely new objects. Object.assign modifies the first argument.

Try replacing return Object.assign(state, { data: newEntities })

with return Object.assign({}, state, { data: newEntities })

If you stick with this, flat data structure is not needed.

Upvotes: 5

Related Questions