Search code examples
reactjsreduxnormalizr

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"
      }
    ]
  }
]

Solution

  • 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.