Reputation: 572
I Would like to bind two child field together. I have created change handler in parent class and passing state value in props of child. whenever i type something in textfield, Parent state and child props are updated i can see that in react dev tool, but child state is not reflected.
Below is my code
class Parent extends React.Component{
constructor(props){
super(props);
this.state = {value: "test"};
this.changeHandler = this.changeHandler.bind(this);
}
changeHandler(value){
this.setState({value: value});
}
render(){
return (
<div>
<Child value={this.state.value} change={this.changeHandler}/>
<Child value={this.state.value} change={this.changeHandler}/>
</div>
);
}
}
class Child extends React.Component{
constructor(props){
super(props);
this.changeHandler = this.changeHandler.bind(this);
this.state = {value: this.props.value};
}
changeHandler(e){
this.setState({value:e.target.value});
this.props.change(e.target.value);
}
render(){
return (
<input type="text" value={this.state.value} onChange={this.changeHandler} />
);
}
}
ReactDOM.render(<Parent/>, document.getElementById('root'));
Upvotes: 0
Views: 110
Reputation: 36985
It's because you are using
class Child extends React.Component{
constructor(props){
super(props);
this.changeHandler = this.changeHandler.bind(this);
// ............... 👇
this.state = {value: this.props.value};
}
// ...
}
Your internal this.state.value
is set only "once" on component mount phase.
(That means, whenever Parent -> this.state.value
changes and causes the Child
components to re-render, this.state = {value: this.props.value};
won't be invoked again)
Instead of using the state in Child component, use the this.props.value
directly on your <Input />
field.
<input type="text" value={this.props.value} onChange={this.changeHandler} />
So the flow is, someone types something in Child.input
, which tells Parent
to update the state, and the change is trickled back down to your Child -> this.props.value
.
And then you notify Parent by calling the passed this.props.changeHandler
.
So the final, Child
component would look like following.
class Child extends React.Component{
constructor(props){
super(props);
this.changeHandler = this.changeHandler.bind(this);
}
changeHandler(e){
this.props.changeHandler({value:e.target.value});
}
render(){
return (
<input type="text" value={this.props.value} onChange={this.changeHandler} />
);
}
}
If you use the ES6 "arrow functions" syntax, you can make it smaller, removing the need for this.changeHandler = this.changeHandler.bind(this)
.
(It's because an arrow function doesn't create its own this
but uses calling context's this
)
class Child extends React.Component{
constructor(props){
super(props);
}
changeHandler = (e) => {
this.props.changeHandler({value:e.target.value});
}
render(){
return (
<input type="text" value={this.props.value} onChange={this.changeHandler} />
);
}
}
Or you can call it directly from onChange
.
class Child extends React.Component {
render() {
return (
<input
type="text"
value={this.props.value}
onChange={this.props.changeHandler}
/>
);
}
}
We can go one step further by converting it to a Function Component (NOT "Functional" component because it doesn't have anything to do with Functional Programming)
function Child({ value, changeHandler}) {
return <input type="text" value={value} onChange={changeHandler} />
}
// or
const Child = ({value, changeHandler}) =>
<input type="text" value={value} onChange={changeHandler} />
And when you use const Child = ...
, make sure that it's declared BEFORE Parent
. But when you use function Child
, it can show up before or after Parent
due to how JavaScript hoisting works.
Lastly, no change in Parent
is needed.
Upvotes: 5
Reputation: 462
You need to implement componentDidUpdate
class Parent extends React.Component{
constructor(props){
super(props);
this.state = {value: "test"};
this.changeHandler = this.changeHandler.bind(this);
}
changeHandler(value){
this.setState({value: value});
}
render() {
return (
<div>
<Child value={this.state.value} change={this.changeHandler}/>
<Child value={this.state.value} change={this.changeHandler}/>
</div>
);
}
}
class Child extends React.Component{
constructor(props){
super(props);
this.changeHandler = this.changeHandler.bind(this);
this.state = {value: this.props.value};
}
changeHandler(e){
this.setState({value:e.target.value});
this.props.change(e.target.value);
}
componentDidUpdate(prevProps) {
if(prevProps.value !== this.props.value) {
this.setState({value: this.props.value});
}
}
render(){
return (
<input type="text" value={this.state.value} onChange={this.changeHandler} />
);
}
}
ReactDOM.render(<Parent/>, document.getElementById('root'));
Upvotes: 2
Reputation: 6052
Each child component has its own independent state. If you want the value to be shared between the two you remove it from state in the children and just use this.props.value in the children. Then value is only mutable in the parent.
Upvotes: 0