4

I have an issue with updating the immutable redux and quite nested data. Here's an example of my data structure and what I want to change. If anyone could show me the pattern of accessing this update using ES6 and spread operator I would be thankful. 😀

const formCanvasInit = {
  id: guid(),
  fieldRow: [{
    id: guid(),
    fieldGroup: [
      { type: 'text', inputFocused: true }, // I want to change inputFocused value
      { type: 'text', inputFocused: false },
    ],
  }],

  // ...
};
5
  • I don't know anything about redux, but as you says it's Immutable, which mean you cannot modify or updating it... :D Commented Feb 1, 2018 at 4:25
  • Immutability in this context means we should not modify data directly, therefore we have to make a shallow copy first then we can modify the copied data. 😁 Commented Feb 1, 2018 at 4:28
  • You don't want a shallow copy; you want a true copy, or edits like this to nested attributes will permeate to the original state, which can lead to issues in flux architecture. Commented Feb 1, 2018 at 4:39
  • @treyhakanson Yes, I mean Copying All Levels of Nested Data. Commented Feb 1, 2018 at 4:52
  • Possible Duplicate of How to update a nested state in React Commented Feb 1, 2018 at 5:42

3 Answers 3

3

This should do the trick, assuming the data is set up exactly as shown, with the given array indices:

const newData = {
   ...formCanvasInit,
   fieldRow: [{
      ...formCanvasInit.fieldRow[0],
      fieldGroup: [
         { ...formCanvasInit.fieldRow[0].fieldGroup[0], inputFocused: newValue },
         ...formCanvasInit.fieldRow[0].fieldGroup.slice(1, formCanvasInit.fieldRow[0].fieldGroup.length)
      ]
   }]
};

If index of the element to be changed is to be determined dynamically, you'll need to use functionality such as filter to find and remove the array element you're updating, and then spread the corresponding subarrays by editing the structure of the call to slice.

Sign up to request clarification or add additional context in comments.

3 Comments

This solution seems to be working, thanks mate. I really appreciate your help. 👍 Would you mind to give me a reference to read? I really need to learn this particular thing.
Not a problem; it's a bit length, but the MDN documentation on the spread operator covers basically everything you'd need to know. Here's a quicker read from the Redux documentation as well
I don't know if this works if we are trying to update something thats not the first index of fieldRow
2

Try using Immutability Helper

I think in your structure, like this

let news = update(formCanvasInit, {
  fieldRow: [{
    fieldGroup: [
     { $set: {type: "number", inputFocused: false}}
    ]
  }]
})

I've tried it Click Me

1 Comment

Thanks, this one also works, I might consider refactoring my codebase using this helper. I have a question, how to get the inputFocused value, because i want to make a toggle for inputFocused, when a certain action is happening. I want to do something like //... inputFocused: !inputFocused How can I achieve that?
1

This is a longer solution but might help you as your redux state grows. I've also changed some of the values in the original state to make a clearer explanation.

const formCanvasInit = {
  id: 'AAAAXXXX',
  fieldRow: [
    {
      id: 1001,
      fieldGroup: [
        {type: 'text1', inputFocused: true}, // I want to change inputFocused value
        {type: 'text2', inputFocused: false},
      ]
    },
    {
      id: 1002,
      fieldGroup: [
        {type: 'text3', inputFocused: true},
        {type: 'text4', inputFocused: true},
      ]
    }
  ]
};

// the id of the field row to update
const fieldRowID = 1001;
// the value of the field type to update
const fieldTypeValue = 'text1';
const fieldRow = [...formCanvasInit.fieldRow];

// obtain the correct fieldRow object
const targetFieldRowIndex = formCanvasInit.fieldRow.findIndex(fR => fR.id === fieldRowID);
let fieldRowObj = targetFieldRowIndex && formCanvasInit.fieldRow[targetFieldRowIndex];

// obtain that fieldRow object's fieldGroup
const fieldGroup = [...fieldRowObj.fieldGroup];

// obtain the correct object in fieldGroup
const fieldIndex = fieldGroup.findIndex(fG => fG.type === fieldTypeValue);
const fieldToChange = fieldIndex && fieldGroup[fieldIndex];

// replace the old object in selected fieldGroup with the updated one
fieldGroup.splice(fieldIndex, 1, {...fieldToChange, inputFocused: false});

// update the target fieldRow object
fieldRowObj = {...fieldRowObj, fieldGroup};

// replace the old fieldGroup in selected fieldRow with the updated one
fieldRow.splice(targetFieldRowIndex, 1, fieldRowObj);

// create the new formCanvasInit state
const newFormCanvasInit = {...formCanvasInit, fieldRow};

3 Comments

I'm a little bit overwhelmed seeing this long code, but it helps me to think in a different way. I appreciate that👍
I'm a bit curious of why you need to store a input's focus state in the reducer. Can you manage this state using the input component's internal state instead?
Honestly, that's not the real data state that I want to use on my app, I just trying to nail the concept of immutability update. This question was one of my way to understand how people solve this kind of case, I want to start with the simplest one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.