Young L.
Young L.

Reputation: 1042

How should I update data in child component which I sent form parent via props

I have one parent component with 4 child components (like SECTIONS). From parent I am sending to every child own section of settings. User can change these settings in each child component. Now my problem is when user changes something like text via input I have to change the original object in the parent. I know one solution is sending method for each field in settings but every section has 5+ more fields so I think this is not a good solution.

This is the relevant part of my render method:


    /**
     * Render method for user profile
     * @return {*}
     */
    render() {
        return (
            <div className={'card p-3 '}>
                <h2 className={'text-center mb-2'}>Všeobecné nastavenia</h2>
                <Form>
                    <Form.Row className={'d-flex '}>
                        <Col md={4} sm={12} className={'order-2 order-md-1'}>
                            <Form.Group className={'d-flex align-items-center justify-content-end'}>
                                <Form.Label className={'mb-0 mr-2 customLabel'}><b>Meno:</b></Form.Label>
                                <Form.Control size="sm" type="text" placeholder="First name"
                                              defaultValue={this.props.userData.firstName}/>
                            </Form.Group>
                            <Form.Group className={'d-flex align-items-center justify-content-end'}>
                                <Form.Label className={'mb-0 mr-2 customLabel'}><b>Priezvisko:</b></Form.Label>
                                <Form.Control size="sm" type="text" placeholder="Last Name"
                                              defaultValue={this.props.userData.lastName}/>
                            </Form.Group>
                            <Form.Group className={'d-flex align-items-center justify-content-end'}>
                                <Form.Label className={'mb-0 mr-2 customLabel'}><b>Email:</b></Form.Label>
                                <Form.Control size="sm" type="text" placeholder="Váš email"
                                              defaultValue={this.props.userData.email}/>
                            </Form.Group>
...

I have to change as said before firstName, lastName etc. values in parent.

Is there a nice way how to do it? Thx for help.

I built this similiar situation in CodeSandbox: https://codesandbox.io/s/kind-panini-06qci?file=/src/App.js

Upvotes: 1

Views: 80

Answers (2)

Stoic Lion
Stoic Lion

Reputation: 480

You have to pass the event handler from parent to child when you want to update the parent's state with values on children. If you want to resolve the communication between the child and its parent, you can simply pass and event handler with two arguments: the name of field and its value. With js you can call field either with dot notation and with bracket notation. In this case you have to use bracket notation and pass as argument the first parameter and as value to store the second.

A bit of code:

In the App component the render looks like this:

render() {
    return (
      <div className="App">
        <Child data={this.state.object} clicked={this.updateValue} />
      </div>
    );

The event handler looks like this:

 updateValue = (field, value) => {
    let update = {};
    update[field] = value;
    this.setState({
      ...this.state,
      object: {
        ...this.state.object,
        update
      }
    });
  };

What does it mean? The first thing the method do is to create an object update containing the update, then it does the shallow copies and, finally, update object merging it with the update.

The code for each Form.Control in child component looks like this:

<Form.Control
          size="sm"
          type="text"
          defaultValue={this.props.data.data1}
          onChange={(event) => this.props.clicked('data1', event.target.value)}
        />

Upvotes: 1

Dr. Acula
Dr. Acula

Reputation: 489

You can set the name for your Form component as per the variable and use it in the event handler like so:

<Form.Control
          name="data1"
          size="sm"
          type="text"
          defaultValue={this.props.data.data1}
          onChange={this.props.handleOnChange}
        />

Handler being something like:

 handleOnChange = (e) => {
    this.setState({object: {...this.state.object, [e.target.name]: e.target.value}})
  }

<Child data={this.state.object} handleOnChange={this.handleOnChange} />

Upvotes: 1

Related Questions