Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Passing child state to parent state

Tags:

reactjs

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:

  • Is this really not allowed?
  • Why should this not be modular and fast?
  • Is this really braking the one-way-dataflow, becoming a two way dataflow?
  • What other problems could happen with this way?
  • 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?
like image 330
fabpico Avatar asked Oct 03 '18 14:10

fabpico


2 Answers

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.

like image 91
gaperton Avatar answered Oct 18 '22 10:10

gaperton


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

like image 34
ramusus Avatar answered Oct 18 '22 08:10

ramusus