Manish Jangir
Manish Jangir

Reputation: 5437

Update deeply nested object property in immutableJS list

I've a following hierarchy of immutable list:

fromJS({
departments: [{
    departmentName: 'PHP',
    employees: [{
        employeeId: 1000,
        employeeName: 'Manish',
        projects: [{
            projectId: 200,
            projectName: 'ABC'
        },
        {
            projectId: 300,
            projectName: 'DEF'
        }]
    }]
}]
})

In this list, I want to update the project name of project ID 200. Though I can update the simple one level of array of objects by finding their indexes but I don't have any idea that how to begin with this one in immutableJS.

Upvotes: 2

Views: 1648

Answers (3)

Nurbol Alpysbayev
Nurbol Alpysbayev

Reputation: 21871

I recommend you either not using immutable.js for such complex data structures, or to refactor the structures to simple collections. Otherwise not only you would suffer from maintenance hell, but performance would be hundreds times worse (but still you might not notice it, depends on your app).

Upvotes: 0

I believe the idiomatic way to do this with Immutable would be to use a lot of .map and .update calls:

const state = fromJS(/*...*/);
const newState = state.update('departments',
  departments => departments.map(
    department => department.update('employees',
      employees => employees.map(
        employee => employee.update('projects',
          projects => projects.map(
            project => project.get('projectId') === 200 ?
            project.set('projectName', 'NEW_PROJECT_NAME') :
            project
          ))))));

const state = Immutable.fromJS({
  departments: [{
    departmentName: 'PHP',
    employees: [{
      employeeId: 1000,
      employeeName: 'Manish',
      projects: [{
          projectId: 200,
          projectName: 'ABC'
        },
        {
          projectId: 300,
          projectName: 'DEF'
        }
      ]
    }]
  }]
})

const newState = state.update('departments',
  departments => departments.map(
    department => department.update('employees',
      employees => employees.map(
        employee => employee.update('projects',
          projects => projects.map(
            project => project.get('projectId') === 200 ?
            project.set('projectName', 'NEW_PROJECT_NAME') :
            project
          ))))));

console.log(newState);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>

Dealing with deeply nested data is annoying. I think you could make your life a lot simpler if you flattened your data structures a bit. Take this structure for example:

const state = fromJS({
  departments: [{
    employeeIds: [ 1000 ]
  }],
  employees: {
    1000: {
      employeeId: 1000,
      employeeName: 'Manish',
      projectIds: [ 200, 300 ]
    }
  },
  projects: {
    200: {
      projectId: 200,
      projectName: 'ABC'
    },
    300: {
      projectId: 300,
      projectName: 'DEF'
    }
  }
});

With a structure like this, the answer to your original question would be as easy as a single updateIn:

const newState = state.updateId(['projects', 200],
  project => project.set('projectName', 'NEW_PROJECT_NAME'));

Upvotes: 0

ageoff
ageoff

Reputation: 2828

I had something similar a long time ago... I used flatMap function. Eventually I modified my state structure as maintaining this code was a nightmare.

updateProduct = (id, newName, data) => {
        return {
            departments: Immutable.flatMap(data.departments, (department => {
                return {
                    ...department,
                    employees: Immutable.flatMap(department.employees, (employee => {
                        return {
                            ...employee,
                            projects: Immutable.flatMap(employee.projects, (project => {
                                if (project.projectId == id) {
                                    return {
                                        ...project,
                                        projectName: newName
                                    }
                                }
                                else {
                                    return {...project}
                                }
                            }))
                        }
                    }))
                }
            }))
        }
    }

Upvotes: 0

Related Questions