43

In React's this.state I have a property called formErrors containing the following dynamic array of objects.

[
  {fieldName: 'title', valid: false}, 
  {fieldName: 'description', valid: true},
  {fieldName: 'cityId', valid: false},
  {fieldName: 'hostDescription', valid: false},
]

Let's say I would need to update state's object having the fieldName cityId to the valid value of true.

What's the easiest or most common way to solve this?

I'm OK to use any of the libraries immutability-helper, immutable-js etc or ES6. I've tried and googled this for over 4 hours, and still cannot wrap my head around it. Would be extremely grateful for some help.

Fellow Stranger
  • 32,129
  • 35
  • 168
  • 232
  • Did you try iterating over the array, and if `fieldName === 'cityId'` then set `valid` to `true`? This seems very straightforward.... what am I missing? It might help if you posted some of the things you've tried. – alexanderbird May 04 '17 at 20:47
  • I am also thinking the same as @alexanderbird, so do you have a specific performance requirement? – Junbang Huang May 04 '17 at 20:48
  • My issue is about dealing with [immutable data](https://facebook.github.io/react/docs/update.html). – Fellow Stranger May 04 '17 at 20:49

4 Answers4

44

You can use map to iterate the data and check for the fieldName, if fieldName is cityId then you need to change the value and return a new object otherwise just return the same object.

Write it like this:

var data = [
    {fieldName: 'title', valid: false}, 
    {fieldName: 'description', valid: true},
    {fieldName: 'cityId', valid: false},
    {fieldName: 'hostDescription', valid: false},
]

var newData = data.map(el => {
                  if(el.fieldName == 'cityId')
                     return Object.assign({}, el, {valid:true})
                  return el
              });

this.setState({ data: newData }); 
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • 3
    Although this would iterate over the entire array regardless of when the item to be updated appears. – Ryan Sep 01 '19 at 00:48
  • You could set a simple flag in that case to optimize and avoid iterating through the whole array. Also you could replace Object.assign with spread operator like return {...el,valid:true} – arp Jun 14 '22 at 17:22
14

Here is a sample example - ES6

The left is the code, and the right is the output

enter image description here

Here is the code below

const data = [
    { fieldName: 'title', valid: false }, 
    { fieldName: 'description', valid: true },
    { fieldName: 'cityId', valid: false }, // old data
    { fieldName: 'hostDescription', valid: false },
]

const newData = data.map(obj => {
  if(obj.fieldName === 'cityId') // check if fieldName equals to cityId
     return {
       ...obj,
       valid: true,
       description: 'You can also add more values here' // Example of data extra fields
     }
  return obj
});

const result = { data: newData }; 

console.log(result);

this.setState({ data: newData });

Hope this helps, Happy Coding!

accimeesterlin
  • 4,528
  • 2
  • 25
  • 18
2

How about immutability-helper? Works very well. You're looking for the $merge command I think.

@FellowStranger: I have one (and only one) section of my redux state that is an array of objects. I use the index in the reducer to update the correct entry:

case EMIT_DATA_TYPE_SELECT_CHANGE:
  return state.map( (sigmap, index) => {
    if ( index !== action.payload.index ) {
      return sigmap;
    } else {
      return update(sigmap, {$merge: {
        data_type: action.payload.value
      }})
    }
})

Frankly, this is kind of greasy, and I intend to change that part of my state object, but it does work... It doesn't sound like you're using redux but the tactic should be similar.

Omortis
  • 1,334
  • 19
  • 44
  • The problem is that I've tried it but cannot understand their syntax how to replace a value in array of objects :/ – Fellow Stranger May 04 '17 at 20:57
  • simply follow the example here: https://github.com/kolodny/immutability-helper#nested-collections. You want to update the `valid` parameter of the object at index 2, so something like `update(formErrors, {2: {valid: {$set: true}}})` – Hamms May 04 '17 at 20:59
  • 1
    or `update(formErrors, {2: {$merge: {valid: true}}})` – Hamms May 04 '17 at 21:03
  • @FellowStranger definitely futz with immutability-helper's update function. Very, very useful. It does take a while to learn the syntax.... – Omortis May 04 '17 at 21:10
1

Instead of storing your values in an array, I strongly suggest using an object instead so you can easily specify which element you want to update. In the example below the key is the fieldName but it can be any unique identifier:

var fields = {
    title: {
        valid: false
    },
    description: {
        valid: true
    }
}

then you can use immutability-helper's update function:

var newFields = update(fields, {title: {valid: {$set: true}}})
FuzzyTree
  • 32,014
  • 3
  • 54
  • 85