0

I am trying to reproduce my original problem.

I have two arrays in react state, and Array1 is the original array from Database and Array2 is the updated array in state.

The objective is to update only changed rate and not quantity (and other properties) back to the Database, hence i need to update the values of rates in object of basicrecipe with the values of the rates in object of recipeBasicRecipe array for a the objects of basicrecipe matching with the objects in recipeBasicRecipe.

I am getting this error when I run the code, request help

Error:Uncaught TypeError: Cannot assign to read only property

let basicRecipes = [
  {
    id: 1,
    name: IceCream,
    details: [{ id: "12", name: "milk", quantity: "50", rate: "100" },
    { id: "13", name: "cream", quantity: "50", rate: "300" }]
  },
  {
      id: 2,
      name: Coffee,
      details: [{ id: "14", name: "Coffee bean", quantity: "60", rate: "200" },
      { id: "15", name: "water", quantity: "60", rate: "300" }]

  },
  {
      id: 3,
      name: Tea,
      details: [{ id: "16", name: "Tea leaf", quantity: "50", rate: "700"      
      }]
}]


let recipeBasicRecipe = [
  {
      id: 1,
      name: IceCream,
      details: [{ id: "12", name: "milk", quantity: "50", rate: "500" },
      { id: "13", name: "cream", quantity: "50", rate: "700" }]
  },
  {
      id: 2,
      name: Coffee,
      details: [{ id: "14", name: "Coffee bean", quantity: "60", rate: "800" },
      { id: "15", name: "water", quantity: "60", rate: "8000" }]
  }
];

let r = basicRecipe;

let Array2 = recipeBasicRecipes;

r = r.map(item => {
  let element = Array2.find(e => e.id == item.id);
  if (element) {
    item.details = item.details.map(e => {
      let detail = element.details.find(d => d.id == e.id);
      if (detail) {
        e.rate = detail.rate;
      }
      return e;
    });
  }
  return item;
});

console.log(r);
Posing the relevant react ccode:

const initialState = {

    basicRecipe: [],

    recipeBasicRecipes: [],
   
  };

  const [state, dispatch] = useReducer(recipeManagementReducer, initialState);


Function where I am executing this code

  const onSubmit = e => {
    e.preventDefault();
    /**
    * 
    setShowLoader();
    updateawMateris(state.recipeRawMaterials);
    *  */

    let r = state.basicRecipe;

    let Array2 = state.recipeBasicRecipes;

    r = r.map(item => {
      let element = Array2.find(e => e._id == item._id);
      if (element) {
        item.details = item.details.map(e => {
          let detail = element.details.find(d => d._id == e._id);
          if (detail) {
            e.rate = detail.rate;
          }
          return e;
        });
      }
      return item;
    });

While playing around I changed the return to make it immutable as that was cause of the errors.

Here is the snippet, only problem is this returns change on Quantity in recipe as well, how do I avoid that

    let r = [...state.basicRecipe];

    let Array2 = [...state.recipeBasicRecipes];

    r = r.map(item => {
      let element = Array2.find(e => e._id === item._id);
      if (element) {
        item.details = item.details.map(e => {
          let detail = element.details.find(d => d._id === e._id);
          if (detail) {
            return {
              ...e,
              rate: detail.rate
            };
          }
          return e;
        });
      }
      return item;
    });

    console.log(r);
3
  • This will help you: stackoverflow.com/questions/27519836/… ... you can further explore here: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Aug 23, 2020 at 21:01
  • Not able to understand where exactly do I make these changes..Can you pls help Commented Aug 23, 2020 at 21:04
  • 1
    I'll have to apologize for the delay, I was a bit busy. I have provided another lead below, please check and see if it works. Commented Aug 23, 2020 at 21:47

1 Answer 1

0

Alright, after doing some research on this for you I came to realize that some of the properties in your returned data are non-writable.

For example the error:

Cannot assign to read only property 'rate' of object '#'

Happens because rate or item e in your map is not mutable. For it to work, you will have to create copy of that data indread of storing it's reference on your variables here:

let r = state.basicRecipe;

let Array2 = state.recipeBasicRecipes;

r and Array2 are just references to your state properties.


You may want to instead make new copies of that data. Like this:

let r = [...state.basicRecipe];

let Array2 = [...state.recipeBasicRecipes];

and then run your code and modify properties that you want to change.


Here is a minimal reproduction of your scenario and I don't get any errors. Please check this and advise?

class Something extends React.Component{

  state = {
     basicRecipes : [
      {
        id: 1,
        name: "IceCream",
        details: [{ id: "12", name: "milk", quantity: "50", rate: "100" },
        { id: "13", name: "cream", quantity: "50", rate: "300" }]
      },
      {
          id: 2,
          name: "Coffee",
          details: [{ id: "14", name: "Coffee bean", quantity: "60", rate: "200" },
          { id: "15", name: "water", quantity: "60", rate: "300" }]

      },
      {
          id: 3,
          name: "Tea",
          details: [{ id: "16", name: "Tea leaf", quantity: "50", rate: "700"      
          }]
    }],
    recipeBasicRecipe : [
      {
          id: 1,
          name: "IceCream",
          details: [{ id: "12", name: "milk", quantity: "50", rate: "500" },
          { id: "13", name: "cream", quantity: "50", rate: "700" }]
      },
      {
          id: 2,
          name: "Coffee",
          details: [{ id: "14", name: "Coffee bean", quantity: "60", rate: "800" },
          { id: "15", name: "water", quantity: "60", rate: "8000" }]
      }
    ]
  };

  constructor(props)
  {
    super(props);
    this.performSomeAction = this.performSomeAction.bind(this);
  }
  
  performSomeAction()
  {
    let r = [...this.state.basicRecipes];
    let Array2 = [...this.state.recipeBasicRecipe];

    return r.map(item => {
      let element = Array2.find(e => e.id === item.id);
      let tempItem = {...item}; // Make a mutable copy of Item
      if (element) {
        tempItem.details = item.details.map(e => {
          let detail = element.details.find(d => d.id === e.id);
          let tempE = {...e}; // Make a mutable copy of e
          
          if (detail) {
            tempE.rate = detail.rate;
          }
          return tempE;
        });
      }
      return tempItem;
    });
  }
  
  render()
  {
    console.log(this.performSomeAction());
    
    return(
      <h1>Code Runs</h1>
    );
  }
}

ReactDOM.render(<Something />, 
document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

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

14 Comments

Alright, Please check the answer again. Unfortunately, I can only work with what you provided and as far as i've tried, the code runs. Otherwise, you'll need to provide a repro that throws those errors and then I can assist.
Yup make some sort of gist on GitHub or show more logs and code please
Well the mistake is because you spread item and not e. You must spread e like this return { ...e, rate: detail.rate} not item.
I have solved that also.. You can do exactly what you did with e for item
|