Reputation: 16416
My component's render()
method is NOT called after a change of state with this.setState()
.
This is the method where the component's state is changed (it is invoked and I have verified this):
handlePhoneNumberChange = name => (event) => {
const { contactPhone } = this.state;
const index = name;
const phoneEntry = contactPhone[index];
phoneEntry.phoneNumber = event.target.value;
this.setState({ contactPhone });
};
This is the component's initial state:
constructor(props) {
super(props);
this.state = {
contactPhone: [{ phoneNumber: '', phoneType: '' }],
};
}
This is how the TextField is rendered:
{contactPhone.map((phone, index) => (
<div key={index}>
<TextField
id={String(Math.random())}
label="Phone number"
type="tel"
value={phone.phoneNumber}
onChange={this.handlePhoneNumberChange(index)}
placeholder="Contact phone number"
margin="normal"
/>
<br />
</div>
))}
Why isn't render being invoked after setState()?
Upvotes: 0
Views: 6364
Reputation: 4373
Your handlePhoneNumberChange
function mutates state directly. The React docs states: Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
The simplest fix is to clone contactPhone, change it and pass it to state
handlePhoneNumberChange = index => (event) => {
const contactPhone = [...this.state.contactPhone]; // at this point contactPhone !== this.state.contactPhone
const phoneEntry = contactPhone[index];
phoneEntry.phoneNumber = event.target.value;
this.setState({ contactPhone });
};
Should work!
const cloneArray = [...someArray]; // spread syntax
is the same as
const cloneArray = someArray.slice(0);
Both produce an array that contains the same values as someArray
but are not the same array.
Upvotes: 4
Reputation: 627
I think you need revisit your handlePhoneNumberChange
function:
You here not making changes, you setting same value twice.
Reference for Array
contactPhone
is same
handlePhoneNumberChange = name => (event) => {
// its destructed, but not changed later
const { contactPhone } = this.state;
// no changes
const index = name;
const phoneEntry = contactPhone[index];
phoneEntry.phoneNumber = event.target.value;
// you set same value, nothing changed
this.setState({ contactPhone });
};
Upvotes: 0
Reputation: 16416
I don't know why it works but it solves it:
I changed:
this.setState({ contactPhone });
To:
this.setState({ contactPhone: [...contactPhone] });
[...contactPhone]
simply creates a new object. But now the render() is being called. Very weird.
Upvotes: 0
Reputation: 6015
You are not modifying the state here. You are setting it to the same value you had initially. Update the code as below.
handlePhoneNumberChange = name => (event) => {
const { contactPhone } = this.state;
const index = name;
const phoneEntry = contactPhone[index];
phoneEntry.phoneNumber = event.target.value;
contactPhone = [...contactPhone,phoneEntry]
this.setState({ contactPhone });
};
Upvotes: 0
Reputation: 1721
It is a terrible idea to assign the list key to a random stringified number, key={String(Math.random())}
, because the key will change with each render call and React will not be able to reconcile the virtual DOM properly when this.setState
is invoked. React keeps track of which list items have changed by diff-ing list items with the same key.
See link below for further details on React reconcilation: https://reactjs.org/docs/reconciliation.html#keys
Upvotes: 0