fabpico
fabpico

Reputation: 2917

React: Passing child state to parent state

I am working since more than a year with React and i have read Thinking in react, Lifting state up, and State and lifecycle.

I have learned that React's concept with data flow is is One-way data flow.

Citates from these pages:

React’s one-way data flow (also called one-way binding) keeps everything modular and fast.

Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:...

If you imagine a component tree as a waterfall of props, each component’s state is like an additional water source that joins it at an arbitrary point but also flows down.

As i understand this, following example is not allowed because i am passing child state data to the parent. But i see some developers working like that:

class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { fromParent: null };
    }

    addSomething(stateValueFromChild) {
        this.setState({fromParent: stateValueFromChild});
    }

    render() {
        return <Child
                addSomething={(stateValueFromChild) => this.addSomething(stateValueFromChild)}>
                 // ...
        </Child>;
    }
}

class Child extends React.Component {
    constructor(props) {
        super(props);
        this.state = { fromChild: 'foo' };
    }

    render() {
        return <Form onSubmit={() => this.props.addSomething(this.state.fromChild)}>
                 // ...
        </Form>;
    }
}

My questions now are:

Upvotes: 9

Views: 8316

Answers (3)

Sagar
Sagar

Reputation: 4957

Your question is absolutely correct, many times developer (including myself) struggled for passing child's components state or props to parent component.

I always do logic for getting next state or next props in child component and pass next state or next props to parent component by using handler functions of parent component.

import React, { Component } from "react";
import { render } from "react-dom";

class Parent extends Component {
  constructor(props) {
    super(props);
    this.handleSomething = this.handleSomething.bind(this); // binding method
    this.state = {
      fromParent: "foo"
    };
  }

  handleSomething(value) {
    this.setState(prevState => {
      return {
        fromParent: value
      };
    });
  }

  render() {
    return (
      <div>
        <h1>State: {this.state.fromParent}</h1>
        <Child handleSomething={this.handleSomething} />
      </div>
    );
  }
}

class Child extends Component {
  constructor(props) {
    super(props);
    this.state = {
      fromChild: "bar"
    };
  }

  render() {
    return (
      <div>
        <button
          onClick={e => {
            const { fromChild } = this.state;
            // do whatever as per your logic for get value from child pass to handleSomething function
            // you can also do same for handling forms
            this.props.handleSomething(fromChild);
          }}
        >
          Click Me
        </button>
      </div>
    );
  }
}

render(<Parent />, document.getElementById("app"));

Upvotes: 0

gaperton
gaperton

Reputation: 3826

Is this really not allowed? Why should this not be modular and fast?

Excellent questions. This is allowed. It's just a bit tricky to make it work right because you've got state synchronization here. In the modern frontend world, the state synchronization is believed to be a very challenging task.

The problem will appear when you'll need to sync the state in two directions. For instance, if this child form is used to edit some element of the list, and you're changing the current element of the list. You'll need the child component to detect that situation and sync its local state with the new element from props during the particular UI update. As long as you don't have that, you're fine.

Is this really braking the one-way-dataflow, becoming a two way dataflow?

Nah, it's not. It's still unidirectional data flow because React can't work in any other way by design; UI updates always coming from top to bottom. In your example, your child triggers an event which causes the parent to update its state (it's totally fine), which will cause the UI update of the parent and the child. If you really violate "unidirectional data flow", you'll feel it. You will get an infinite loop or something similar.

When i would lift the state up, how would you solve following case; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using?

Yep, that's what they mean by "lifting the state". You organize your root state as a tree reflecting the state of the children, then pass down elements of the state to children along with callbacks to modify the root state.

Upvotes: 3

ramusus
ramusus

Reputation: 8305

It's allowed and there is nothing wrong with your code, but I would not call it passing state from child to parent. All you do is invoking method passed in props and triggered by event with some argument, which in your example is child's state value, but it could be any other variable. Parent component knows nothing about nature of this argument, it just receives the value and able to do anything with it, for example change it's own state to another. If Child's state will change, Parent is not going to receive this update without onSubmit event fired again. But children always receive updates from the parent and automatically get rerendered, when props get changed. And of course some of the props could be states of some parents. Here is the major difference in behavior.

There is a good article explaining this in details: Props down, Events Up

Upvotes: 1

Related Questions