Abhinav Rai
Abhinav Rai

Reputation: 130

React child component state updates parent component state

Why child state data change updates parent state data?

I want to update parent data only after child form is complete.

export default class StepOne extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            data: this.props.data
        }
        this.handleChanges = this.handleChanges.bind(this);
    }
    handleChanges(e){
        var data = this.state.data
        console.log(this.props.data) //{loan_amount: "", validate: false}
        var name = e.target.name
        var value = e.target.value
        data[name] = e.target.value
        this.setState({data})
        console.log(this.props.data) //{loan_amount: "1", validate: false}
    }
    render() {
        return (
            <div>
                <h4 className="form-ques">Loan Details</h4>
                <Row>
                    <Input label="Required Amount" type="number" name="loan_amount" onChange={this.handleChanges} value={this.state.data.loan_amount}/>
                </Row>
            </div>
    )}
}

Upvotes: 0

Views: 148

Answers (3)

Shubham Khatri
Shubham Khatri

Reputation: 281666

The Reason that your parent state changes based on the child is that you are mutating the state and thus the props directly

constructor(props){
    super(props)
    this.state = {
        data: this.props.data .  // <-- props are assigned to state by reference here
    }
    this.handleChanges = this.handleChanges.bind(this);
}
handleChanges(e){
    var data = this.state.data .  // <-- the state data and thus the prop data are assigned to data by reference here
    console.log(this.props.data) //{loan_amount: "", validate: false}
    var name = e.target.name
    var value = e.target.value
    data[name] = e.target.value // <-- since data references state and prop directly you are modifying them both by modifying data.
    this.setState({data})
    console.log(this.props.data) //{loan_amount: "1", validate: false}
}

The solution is simple, you need to clone the object state data instead of directly assigning it using spread syntax

handleChanges(e){
    var data = {...this.state.data} //Spread syntax creates a new object for you 
    console.log(this.props.data) 
    var name = e.target.name
    var value = e.target.value
    data[name] = e.target.value
    this.setState({data})
    console.log(this.props.data) 
}

Upvotes: 1

basifat
basifat

Reputation: 19

From your question it is not obvious what is your parent component or your child component. If this code represents your child component, then you need to move the handleChanges(e) to the parent component because now you are setting the child state, instead of the parent state.

Upvotes: 1

Adeel Imran
Adeel Imran

Reputation: 13966

Rather then doing it like this you can do something like this

export default class StepOne extends React.Component{
constructor(props){
   super(props)
   // You don't need the state here
   //this.state = {
   // data: this.props.data
   //}
   this.handleChanges = this.handleChanges.bind(this);
}

// you don't need this here as well
handleChanges(e){
   //var data = this.state.data
   //console.log(this.props.data) //{loan_amount: "", validate: false}
   //var name = e.target.name
   //var value = e.target.value
   //data[name] = e.target.value
   //this.setState({data})
   //console.log(this.props.data) //{loan_amount: "1", validate: false}
}

render() {
    const { loan_amount, validate } = this.props.data;
    return (
      <div>
        <h4 className="form-ques">Loan Details</h4>
        <Row>
          <Input 
           label="Required Amount" 
           type="number" 
           name="loan_amount" 
           onChange={this.props.onHandleChange} //New method to change value 
           value={loan_amount} // Getting this value from props
          />
       </Row>
     </div>
)}

Then in your parent class where you have defined everything you create a function called.

onHandleChange = (e) => {
   var data = this.state.data;
   data[e.target.name] = e.target.value;
   this.setState({ data });
}

This way every time you change your child component, only one data field is change that being in your parent component, and your parent component is the one updating/changing the form.

I hope it helps please do let me know if you still have any questions.

Upvotes: 0

Related Questions