Reputation: 4501
My goal is to
To achieve the second goal, I use getDerivedStateFromProps
the following way
https://codepen.io/jedgar-nawasardqn/pen/VRpWrZ?editors=1011
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {
value: "default valu"
}
}
onChange = (value) => {
this.setState({
value: value
})
}
render() {
return (
<div>
<form>
<label>Parent: </label>
<input
value={this.state.value}
onChange={(e) => this.onChange(e.target.value)}/>
</form>
<Child
value={this.state.value}/>
</div>);
}
}
class Child extends React.Component {
constructor(props) {
super(props)
this.state = {
value: this.props.value
}
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log('nextProps', nextProps)
return {
value: nextProps.value
}
}
onChange = (value) => {
console.log('CHild changed')
this.setState({
value: value
})
}
render() {
return (
<div>
<label>Child: </label>
<input
value={this.state.value}
onChange={(e) => this.onChange(e.target.value)}/>
</div>)
}
}
React.render(<Parent/>, document.getElementById('app'));
...but for some reason I can't make it work. Any suggestions ?
Upvotes: 0
Views: 120
Reputation: 2918
Assuming I understood your goals of wanting to have a parent input control a child input when the parent changes, but allowing the child input to change itself and not affect the parent:
The problem is that getDerivedStateFromProps
gets called regardless so when you are changing the state from the Child's input, getDerivedStateFromProps
is immediately reverting it back to the Parent's value. You should use componentDidUpdate
and diff the props rather than using getDerivedStateFromProps
and only update the Child's state to match the Parent's when the Parent's state actually changes.
I made a Code Sandbox based on your Fiddle to demonstrate this: https://codesandbox.io/s/m5qj6qq769?fontsize=14
Upvotes: 1
Reputation: 1768
First, even if it's not about your question, I suggest you to not use an arrow function inside the render()
method, so, instead of writing onChange={(e) => this.onChange(e.target.value)} />
, you should just write onChange={this.onChange} />
. The reason is that the arrow function would be created and then discarded at every render()
: not a big deal if we have few renders and few arrow functions, but.. It's better to avoid waste of computational power :)
Now, about your question! Honestly, it seems that the Child
Component just need to show the value, thus, it's not really useful to "copy" the value from Parent
Component to Child
Component: you can just keep your values in the Parent
Component, and then refers to that value in both Parent
and Child
Component.
To do this, you need to pass an handler function also to the Child
Component.
Let's look at the fiddle!
class Child extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<label>Child: </label>
<input
value={this.props.value}
onChange={this.props.handleChange}/>
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {value: "Default Value"};
}
handleChange = (e) => {
this.setState({value: e.target.value});
}
render() {
return (
<div>
<form>
<label>Parent: </label>
<input
value={this.state.value}
onChange={this.handleChange} />
</form>
<Child
value={this.state.value}
handleChange={this.handleChange} />
</div>
);
}
}
ReactDOM.render(<Parent />, document.getElementById('root'));
@import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id='root'></div>
Upvotes: 0