bp123
bp123

Reputation: 3417

componentDidUpdate isn't recognising state change

When supplier._id changes, the componentDidUpdate doesn't recognise the update. Is this because it's nested? What am I missing here?

Path: React.js

constructor(props) {
  super(props);

  this.state = {
    supplier: {
      _id: '',
      name: ''
    }
  };
  this.handleUpdateForm = this.handleUpdateForm.bind(this);
}    


componentDidUpdate(prevProps, prevState) {
      const { supplier } = this.state;
    
      if (prevState.supplier._id !== supplier._id) {
        console.log('Supplier id changed');
      }
    }
    
    handleUpdateForm(fieldsToUpdate, inputName, inputValue) {
      let { supplier, suppliers } = this.state;
    
      if (fieldsToUpdate === 'supplierFields') {
        if (inputName === 'supplier_id') {
          const selectedSupplier =
            inputName === 'supplier_id'
              ? suppliers.find((supplier) => supplier._id === inputValue)
              : null;
    
          supplier = Object.assign(supplier, selectedSupplier);
        } else {
          supplier._id = inputName === 'name' ? '' : supplier._id;
    
          supplier = Object.assign(supplier, {
            [inputName]: inputValue
          });
        }
      }
    
      this.setState({
        supplier
      });
    }

Upvotes: 1

Views: 118

Answers (3)

Abhay Sehgal
Abhay Sehgal

Reputation: 1723

The issue is in this part of code

 supplier = Object.assign(supplier, {
        [inputName]: inputValue
 });

Object.assign takes the first parameter as target and the rest are sources, means 1st parameter object reference will be taken so you're updating the supplier object directly and that's why it's not calling componentDidUpdate. try this -

 supplier = Object.assign({}, supplier, {
        [inputName]: inputValue
 });

By above snippet a new object will be created

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202696

Issue - State Mutation

In supplier = Object.assign(supplier, selectedSupplier);, supplier is the state reference. You "merge" selectedSupplier into that referenced object. This mutates the state object, supplier. Object.assign returns the target object, which you save back to supplier, and then update state. The object reference for supplier never changes.

Solution - Shallow copy supplier state then update

handleUpdateForm(fieldsToUpdate, inputName, inputValue) {
  let { supplier, suppliers } = this.state;

  if (fieldsToUpdate === 'supplierFields') {
    if (inputName === 'supplier_id') {
      const selectedSupplier =
        inputName === 'supplier_id'
          ? suppliers.find((supplier) => supplier._id === inputValue)
          : null;

      if (selectedSupplier) {
        supplier = {
          ...supplier, // <-- shallow copy existing state
          ...selectedSupplier, // <-- merge new supplier data
        };
      }
    } else {
      supplier = {
        ...supplier, // <-- shallow copy existing state
        _id: inputName === 'name' ? '' : supplier._id // <-- update property
        [inputName]: inputValue, // <-- merge input update
      };
    }
  }

  this.setState({
    supplier
  });
}

Upvotes: 2

lanxion
lanxion

Reputation: 1430

Most likely the issue lies in how you are setting the state and how you are extracting the values of the state. Since you are using

this.setState({
    supplier
  });

you are not merging the state with your supplier property. So your state is bound to look like this after using setState:

state = {
  _id: "XXXXXXXXX",
  name: "XXXXXXXX",
  supplier:{
    _id: '',
    _name: ''
  }
}

So, in order to fix this, you should change your setState to immutably set state on the supplier property like:

this.setState({
        supplier: {...supplier}
      });

The main thing to remember is, setState merges whatever changes you put in for a property with the rest of the state.

Upvotes: 0

Related Questions