83

I have a form that has a submit button. That form calls a function onclick that sets the state of something from false to true. I then want to pass this state back to the parent so that if it is true it renders componentA but if it is false it renders componentB.

How would I do that in react? I know I need to use state or props but not sure how to do it. also is this contradicting the one-way flow react principle??

ComponentA code:

<form onSubmit={this.handleClick}>


handleClick(event) {
    this.setState({ decisionPage: true });
    event.preventDefault();
  };

Parent component that controls what it displays:

return (
      <div>
      {this.props.decisionPage ?
        <div>
          <LoginPage />
        </div>
        :
        <div>
          <Decision showThanks={this.props.showThanks}/>
        </div>
      }
      </div>
    )
Kamil Naja
  • 6,267
  • 6
  • 33
  • 47
The worm
  • 5,580
  • 14
  • 36
  • 49

10 Answers10

75

Move handleClick to the parent and pass it to the child component as a prop.

<LoginPage handleClick={this.handleClick.bind(this)}/>

Now in the child component:

<form onSubmit={this.props.handleClick}>

This way submitting the form will update the state in parent component directly. This assumes you don't need to access updated state value in child component. If you do, then you can pass the state value back from the parent to the child as a prop. One-way data flow is maintained.

<LoginPage  handleClick={this.handleClick.bind(this)} decisionPage={this.state.decisionPage}/>
Rami Enbashi
  • 3,526
  • 1
  • 19
  • 21
  • 10
    Good answer :) I'd also recommend the asker of the question reads [Lifting State Up](https://facebook.github.io/react/docs/lifting-state-up.html) and [Thinking in React](https://facebook.github.io/react/docs/thinking-in-react.html) from the official docs for more info on the reasoning behind doing things this way. – Joe Clay Nov 21 '16 at 14:41
  • @RamiEnbashi but how does this change the state of decisionPage to true and thus render the render function inside that component? – The worm Nov 21 '16 at 14:54
  • @RamiEnbashi I have console.logged and I can see state changing to true but how do you tell it, if this is true render the above component? – The worm Nov 21 '16 at 14:59
  • 3
    The links posted by @joe-clay are excellent. Keep the logic of conditional rendering in parent component the same way you already have it. By moving `handleClick` to the parent, you are changing the state of that parent component even if you are triggering the change from the child component. `this` in `handleClick` refers to the component where the the function is declared and not the component that calls it. – Rami Enbashi Nov 21 '16 at 15:02
  • @RamiEnbashi cheers bud. got it working now with a ternary operator, not sure if needed but working :) – The worm Nov 21 '16 at 15:17
  • This way of passing props( `Callbacks`) can also be used to pass data between sibling components. see https://stackoverflow.com/a/54264828/8810941 – Pavindu May 25 '19 at 05:24
  • It's arguably best not just simply move the handler to the parent. I'd probably rather call it `onLogin()` and pass only the needed data, if any. And `preventDefault()` in the child. – x-yuri Mar 22 '21 at 02:22
  • Although this is a valid solution, it doesn't answer the question. Sometimes it's too expensive to update parent state, especially if you have multiple components using the same parent state. So unfortunately, this isn't a valid answer. – Manny Alvarado Mar 10 '22 at 19:01
35

Pass State as a Prop

I have recently learned a method that works great for changing state in a <Parent /> component from a <Child /> component.

This might not be the exact answer for this question, but it is surely applicable to this situation and other similar situations.

It works like this:

set the default STATE in the <Parent /> component - Then add the 'setState' attribute to the <Child />

const Parent = () => {
  const [value, setValue] = useState(" Default Value ");
   return (
    <Child setValue={setValue} />
  )
}

Then change the state(in Parent) from the Child component

const Child = props => {
  return (
   <button onClick={() => props.setValue(" My NEW Value ")}>
    Click to change the state
  </button>
 )
}

When you click the button, the state in the <Parent /> component will change to whatever you set the state to in the <Child /> component, making use of "props".. This can be anything you want.

I Hope this helps you and other devs in the future.

Michiel J Otto
  • 2,121
  • 17
  • 13
12

In Parent Component:

getDatafromChild(val){
    console.log(val);
}
render(){
 return(<Child sendData={this.getDatafromChild}/>);
}

In Child Component:

callBackMethod(){
   this.props.sendData(value);
 }
Ankit Kumar Rajpoot
  • 5,188
  • 2
  • 38
  • 32
7

Simple Steps:

  1. Create a component called Parent.
  2. In Parent Component create a method that accepts some data and sets the accepted data as the parent's state.
  3. Create a component called Child.
  4. Pass the method created in Parent to child as props.

  5. Accept the props in parent using this.props followed by method name and pass child's state to it as argument.

  6. The method will replace the parent's state with the child's state.
barbsan
  • 3,418
  • 11
  • 21
  • 28
Aftab22
  • 550
  • 6
  • 8
  • I really like this answer, but could you give more detail in step 5? – Tricky May 20 '19 at 19:37
  • 2
    @Tricky Created this code to demonstrate the steps. Hope this helps. Thanks. https://codesandbox.io/s/flamboyant-sun-839f8 – Aftab22 May 28 '19 at 11:12
  • 1
    @Aftab22 When you type in the input, "Data from Child" is always one step behind because setState() in React is asynchronous https://stackoverflow.com/a/38558311/704387 I haven't been able to fix this yet though. – Jérôme Oudoul Jul 12 '19 at 21:31
  • @JérômeOudoul I agree, I too noticed this asynchronous behavior and am unable to fix it. – Aftab22 Sep 20 '19 at 07:52
  • Please provide a proper code example. – Lasse Nielsen Feb 12 '22 at 10:11
6

Here is an example of how we can pass data from child to parent (I had the same issue and use come out with this )

On parent, I have a function (which I will call from a child with some data for it)

handleEdit(event, id){ //Fuction
    event.preventDefault();  
    this.setState({ displayModal: true , responseMessage:'', resId:id, mode:'edit'});  
 } 

dishData = <DishListHtml list={products} onDelete={this.handleDelete} onEdit={(event, id) => this.handleEdit(event, id)}/>;

At the child component :

<div to="#editItemDetails" data-toggle="modal" onClick={(event)=>this.props.onEdit(event, listElement.id) }
                        className="btn btn-success">
Abhinav bhardwaj
  • 2,657
  • 25
  • 21
5

In React you can pass data from parent to child using props. But you need a different mechanism to pass data from child to parent.

Another method to do this is to create a callback method. You pass the callback method to the child when it's created.

class Parent extends React.Component {
myCallback = (dataFromChild) => {
    //use dataFromChild
},
render() {
    return (
        <div>
             <ComponentA callbackFromParent={this.myCallback}/>
        </div>
    );
  }
}

You pass the decisionPage value from the child to the parent via the callback method the parent passed.

     class ComponentA extends React.Component{
          someFn = () => {
            this.props.callbackFromParent(decisionPage);
          },
          render() {
            [...]
          }
     };

SomeFn could be your handleClick method.

Daneesha
  • 313
  • 4
  • 10
0

if your parent component is a functional component you can now use the use context way. Which involves passing the ref to the object and the ref to the stateChanging method. What this will allow you to do is change state from parrent in child and also ref tht state while remaining synced with Parent State. You can learn more about this in a youtubeVideo by codedamn titled 'React 16.12 Tutorial 20: Intro to Context API' and 'React 16.12 Tutorial 21: useContext'

UncleFifi
  • 825
  • 1
  • 6
  • 9
0

This works exactly what I wanted. But in case of set of data with say 50 records with (customer_id, customer_name) as values to be updated from child to parent, then this lags. Do the setState using React.useEffect in child component

Supriya Kalghatgi
  • 371
  • 1
  • 3
  • 6
0

i have same problem and so performed this code : in Parent const PARENT = () => { const [value, setValue] = useState("...."); return ( ) } in Child

const CHILD = props => {
  return (
   <button onClick={() => props.setValue("....")}>
    Click to change the state
  </button>
 )
}
0

if your parent and child components use their data there is three way:

  1. define state in parent component and pass it to child as above answer
  2. use Context and Reducer
  3. use Redux (recommended for persist data and complex components)
mohsen solhnia
  • 366
  • 3
  • 15