Reputation: 5445
Trying to set up something simple.
Parent: app.js
class App extends React.Component {
constructor(props) {
super(props);
//This acts as our global state
this.state = {
username: "",
email: "",
bio: ""
};
}
componentDidMount() {
setTimeout(() => {
this.setState({
username: "jonny",
email: "[email protected]",
bio: "My bio...."
});
}, 5000);
}
handleFormChange = data => {
this.setState(data);
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Form data={this.state} onHandleFormChange={this.handleFormChange} />
<p>Name from App state: {this.state.username}</p>
<p>Email from App state: {this.state.email}</p>
<p>Bio from App state: {this.state.bio}</p>
</div>
);
}
}
Child: form.js
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
...this.props.data
};
}
handleSubmit = e => {
e.preventDefault();
};
handleChange = e => {
this.props.onHandleFormChange({ [e.target.name]: e.target.value });
};
// static getDerivedStateFromProps(nextProps, prevState) {
// console.log(nextProps.data)
// return {
// ...nextProps.data
// };
// }
componentDidUpdate(prevProps) {
if (prevProps.data !== this.props.data) {
this.setState({ ...this.props.data });
}
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
name="username"
defaultValue={this.state.username}
onChange={this.handleChange}
/>
<input
type="email"
name="email"
defaultValue={this.state.email}
onChange={this.handleChange}
/>
<textarea
name="bio"
defaultValue={this.state.bio}
onChange={this.handleChange}
/>
<input type="submit" value="submit" />
</form>
</div>
);
}
}
I created an artificial API call by using a setTimeout()
in this example and I'm trying to set the state of the parent with the result of the API call. Then I wish to pass that as a prop to the child...
It's working except in the case of a textarea
. I can see it if I inspect the DOM but it doesn't actually show in the browser...
Note the "my bio..." in the inspector, but the textarea being empty in the browser.
I've tried componentWillUpdate()
, componentDidUpdate()
and getDerivedStateFromProps()
but nothing seems to work.
What am I missing?
Note: I am not using value=""
because then it stops me typing and this form is supposed to allow you to update existing values
Sandbox... https://codesandbox.io/s/ancient-cloud-b5qkp?fontsize=14
Upvotes: 0
Views: 377
Reputation: 15698
It seems to work fine by using the value
attribute instead of defaultValue
. The defaultValue
attribute should really only be used sparingly, since you almost always want your inputs to connect to component state. The optimal way to create a controlled input is by using value
.
<textarea
name="bio"
value={this.state.bio}
onChange={this.handleChange}
/>
Upvotes: 3