By wklm


2016-02-21 14:17:52 8 Comments

My structure looks as follows:

Component 1  

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5  

Component 3

Component 3 should display some data depending on state of Component 5. Since props are immutable, I can't simply save it's state in Component 1 and forward it, right? And yes, I've read about redux, but don't want to use it. I hope that it's possible to solve it just with react. Am I wrong?

10 comments

@Александр Немков 2019-07-11 18:53:07

I've used a top rated answer from this page many times, but while learning React, i've found a better way to do that, without binding and without inline function inside props.

Just look here:

class Parent extends React.Component {

  constructor() {
    super();
    this.state={
      someVar: value
    }
  }

  handleChange=(someValue)=>{
    this.setState({someVar: someValue})
  }

  render() {
    return <Child handler={this.handleChange} />
  }

}

export const Child = ({handler}) => {
  return <Button onClick={handler} />
}

The key is in an arrow function:

handleChange=(someValue)=>{
  this.setState({someVar: someValue})
}

You can read more here. Hope this will be useful for somebody =)

@Rajan Twanabashu 2016-06-30 06:55:59

When ever you require to communicate between child to parent at any level down, then it's better to make use of context. In parent component define the context that can be invoked by the child such as

In parent component in your case component 3

static childContextTypes = {
        parentMethod: React.PropTypes.func.isRequired
      };

       getChildContext() {
        return {
          parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
        };
      }

parentMethod(parameter_from_child){
// update the state with parameter_from_child
}

Now in child component (component 5 in your case) , just tell this component that it want to use context of its parent.

 static contextTypes = {
       parentMethod: React.PropTypes.func.isRequired
     };
render(){
    return(
      <TouchableHighlight
        onPress={() =>this.context.parentMethod(new_state_value)}
         underlayColor='gray' >   

            <Text> update state in parent component </Text>              

      </TouchableHighlight>
)}

you can find Demo project at repo

@Ashish Kamble 2019-06-12 04:34:22

I cant able to understand this answer, can you explain more about it

@Ivan 2016-02-21 15:03:54

For child-parent communication you should pass a function setting the state from parent to child, like this

class Parent extends React.Component {
  constructor(props) {
    super(props)

    this.handler = this.handler.bind(this)
  }

  handler(someValue) {
    this.setState({
      someVar: someValue
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {this.props.handler}/ >
  }
}

This way the child can update the parent's state with the call of a function passed with props.

But you will have to rethink your components' structure, because as I understand components 5 and 3 are not related.

One possible solution is to wrap them in a higher level component which will contain the state of both component 1 and 3. This component will set the lower level state through props.

@chemook78 2017-02-24 17:49:53

why do you need this.handler = this.handler.bind(this) and not just the handler function that sets the state?

@Ivan 2017-02-24 20:54:56

@chemook78 in ES6 React classes methods do not auto-bind to class. So if we don't add this.handler = this.handler.bind(this) in constructor, this inside the handler function will reference the function closure, not the class. If don't want to bind all your functions in constructor, there are two more ways to deal with this using arrow functions. You could just write the click handler as onClick={()=> this.setState(...)}, or you could use property initialisers together with arrow functions as described here babeljs.io/blog/2015/06/07/react-on-es6-plus under "Arrow functions"

@Tamb 2017-06-01 02:03:13

Here's an example of this in action: plnkr.co/edit/tGWecotmktae8zjS5yEr?p=preview

@Vincent Buscarello 2017-07-03 22:21:40

That all makes sense, why e.preventDefault ? and does that require jquery?

@CiccioMiami 2018-03-15 08:57:13

@Ivan, I also always bind the callback function that updates the parent state with this but today I noticed that I forgot to do it in a piece of code and the state of the parent is updated anyway. I am struggling to understand why

@ThisGuyCantEven 2018-05-02 17:29:34

Quick question, does this disallow the assignment of a local state within the child?

@Dan Esparza 2018-11-30 15:36:00

@VincentBuscarello -- I'm asking the same question about e.preventDefault. But I do know that it doesn't require jQuery -- it's built into the browser

@Ivan 2018-11-30 15:56:34

@DanEsparza e.preventDefault does what it says, it prevents the default event from happening. For example you can have a form with a submit button inside. The default behaviour for the submit button is adding parameters for form url and reloading the page. A lot of times you don't want that in an app, but instead you want to fire a request. This is what prevetDefault is needed for.

@Dan Esparza 2018-11-30 16:06:19

@Ivan thanks. :-) I know what it's used for, I was just confused about its usage in this example (because there are no forms referenced). Thanks for the clarification.

@Ivan 2018-11-30 18:19:56

@DanEsparza Well, I guess I just got too used putting preventDefault everywhere. It's not really required in the example. I think I will even remove it now, looks like this question gets a lot of traffic and if people get confused by preventDefault there's sense keeping it.

@Kramer 2019-01-18 12:11:34

How to pass Paramter also in this hander = parameter =>{console.log(parameter)} then in child component I tried Button onclick={()=>this.props.handler("Search")} />

@Ivan 2019-01-18 16:52:40

@Kramer You can bind the function to pass a parameter like this <Button onClick={this.props.handler.bind(this, "Search")}>

@Kc Gibson 2019-05-15 10:13:23

shouldn't handler contain 'someValue'. E.g handler(someValue) { ?

@Ivan 2019-05-16 12:35:45

@KcGibson Right, thank you for pointing out. I'll update the example

@Vishal Bisht 2019-04-26 12:29:55

It seems that we can only pass data from parent to child as react promotes Unidirectional Data Flow, but to make parent update itself when something happens in its "child component", we generally use what is called a "callback function".

We pass the function defined in the parent to the child as "props" and call that function from the child triggering it in the parent component.

-------------------------------------------------------------------------------

class Parent extends React.Component {
  handler = (Value_Passed_From_SubChild) => {
    console.log("Parent got triggered when a grandchild button was clicked");
    console.log("Parent->Child->SubChild");
    console.log(Value_Passed_From_SubChild);
  }
  render() {
    return <Child handler = {this.handler} />
  }
}
class Child extends React.Component {
  render() {
    return <SubChild handler = {this.props.handler}/ >
  }
}
class SubChild extends React.Component { 
  constructor(props){
   super(props);
   this.state = {
      somethingImp : [1,2,3,4]
   }
  }
  render() {
     return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
  }
}
React.render(<Parent />,document.getElementById('app'));

 HTML
 ----
 <div id="app"></div>

In this example we can make data pass from SubChild -> Child -> Parent by passing function to its direct Child.

@Ardhi 2019-02-07 05:53:47

I want to thank the most upvoted answer for giving me the idea of my own problem basically the variation of it with arrow function and passing param from child component:

 class Parent extends React.Component {
  constructor(props) {
    super(props)
    // without bind, replaced by arrow func below
  }

  handler = (val) => {
    this.setState({
      someVar: val
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {() => this.props.handler('the passing value')}/ >
  }
}

Hope it helps someone.

@Ashish Kamble 2019-05-20 05:50:22

whats special about the arrow function over direct call ?

@CPHPython 2019-06-11 13:14:25

@AshishKamble the this in arrow functions refers to the parent's context (i.e. Parent class).

@Roman 2017-03-02 08:23:41

I found the following working solution to pass onClick function argument from child to the parent component:

Version with passing a method()

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div><button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component {

    constructor(props) {
        super(props);
        var handleToUpdate  = this.handleToUpdate.bind(this);
        var arg1 = '';
    }

    handleToUpdate(someArg){
            alert('We pass argument from Child to Parent: ' + someArg);
            this.setState({arg1:someArg});
    }

    render() {
        var handleToUpdate  =   this.handleToUpdate;

        return (<div>
                    <ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

Look at JSFIDDLE

Version with passing an Arrow function

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div>
          <button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component { 
    constructor(props) {
        super(props);
    }

    handleToUpdate = (someArg) => {
            alert('We pass argument from Child to Parent: ' + someArg);
    }

    render() {
        return (<div>
            <ChildB handleToUpdate = {this.handleToUpdate} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

Look at JSFIDDLE

@Dane 2017-10-14 13:46:39

This one is good! could you explain this piece: <ChildB handleToUpdate = {handleToUpdate.bind(this)} /> Why had to bind again ?

@Casey 2018-03-14 21:37:40

@Dane - you have to bind the context of this to be the parent so that when this is called inside the child, this refers to the parent's state and not the child's. This is closure at its finest!

@Dane 2018-03-15 04:18:51

@Casey but aren't we doing that in the constructor ? And isn't that enough ??

@Casey 2018-03-15 04:20:07

You're totally right! I missed that. Yes, if you did it in the constructor already then you're good to go!

@adamj 2018-07-01 00:47:52

You're a legend mate! This'll keep components nicely self contained without having to be forced to create parent components to handle the state exchanges

@Augusto Samamé Barrientos 2018-12-10 13:10:40

+1 for showing how to actually pass a parameter up to the parent in order to set state in the parent (see JsFiddle). Couldn't figure it out with the more widely accepted answer

@Sachin Metkari 2018-10-06 10:16:55

-We can create ParentComponent and with handleInputChange method to update the ParentComponent state. Import the ChildComponent and we pass two props from parent to child component ie.handleInputChange function and count.

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.state = {
      count: '',
    };
  }

  handleInputChange(e) {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  }

  render() {
    const { count } = this.state;
    return (
      <ChildComponent count={count} handleInputChange={this.handleInputChange} />
    );
  }
}
  • Now we create the ChildComponent file and save as ChildComponent.jsx. This component is stateless because the child component doesn't have a state. We use the prop-types library for props type checking.

    import React from 'react';
    import { func, number } from 'prop-types';
    
    const ChildComponent = ({ handleInputChange, count }) => (
      <input onChange={handleInputChange} value={count} name="count" />
    );
    
    ChildComponent.propTypes = {
      count: number,
      handleInputChange: func.isRequired,
    };
    
    ChildComponent.defaultProps = {
      count: 0,
    };
    
    export default ChildComponent;
    

@Bobort 2019-01-28 17:22:11

How does this work when the child has a child that affects the prop of its parent?

@suresh 2017-12-05 17:09:12

<Footer 
  action={()=>this.setState({showChart: true})}
/>

<footer className="row">
    <button type="button" onClick={this.props.action}>Edit</button>
  {console.log(this.props)}
</footer>

Try this example to write inline setState, it avoids creating another function.

@H. parnian 2017-08-23 18:11:52

I found the following working solution to pass onClick function argument from child to the parent component with param:

parent class :

class Parent extends React.Component {
constructor(props) {
    super(props)

    // Bind the this context to the handler function
    this.handler = this.handler.bind(this);

    // Set some state
    this.state = {
        messageShown: false
    };
}

// This method will be sent to the child component
handler(param1) {
console.log(param1);
    this.setState({
        messageShown: true
    });
}

// Render the child component and set the action property with the handler as value
render() {
    return <Child action={this.handler} />
}}

child class :

class Child extends React.Component {
render() {
    return (
        <div>
            {/* The button will execute the handler function set by the parent component */}
            <Button onClick={this.props.action.bind(this,param1)} />
        </div>
    )
} }

@ilans 2017-11-26 06:52:22

Can anyone tell whether that's an acceptable solution (particularly interested in passing the parameter as suggested).

@Ashish Kamble 2019-06-12 08:31:56

param1 is just display on console not get assign it always assigns true

@Matt Styles 2016-02-21 15:18:43

I like the answer regarding passing functions around, its a very handy technique.

On the flip side you can also achieve this using pub/sub or using a variant, a dispatcher, as Flux does. The theory is super simple, have component 5 dispatch a message which component 3 is listening for. Component 3 then updates its state which triggers the re-render. This requires stateful components, which, depending on your viewpoint, may or may not be an anti-pattern. I'm against them personally and would rather that something else is listening for dispatches and changes state from the very top-down (Redux does this, but adds additional terminology).

import { Dispatcher } from flux
import { Component } from React

const dispatcher = new Dispatcher()

// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
  state = {
    text: 'foo'
  } 

  componentDidMount() {
    dispatcher.register( dispatch => {
      if ( dispatch.type === 'change' ) {
        this.setState({ text: 'bar' })
      }
    }
  }

  render() {
    return <h1>{ this.state.text }</h1>
  }
}

// Click handler
const onClick = event => {
  dispatcher.dispatch({
    type: 'change'
  })
}

// Component 5 in your example
const StatelessChild = props => {
  return <button onClick={ onClick }>Click me</button> 
}

The dispatcher bundles with Flux is very simple, it simply registers callbacks and invokes them when any dispatch occurs, passing through the contents on the dispatch (in the above terse example there is no payload with the dispatch, simply a message id). You could adapt this to traditional pub/sub (e.g. using the EventEmitter from events, or some other version) very easily if that makes more sense to you.

@wklm 2016-02-21 20:06:33

My Reacts components are "running" in browser like in an official tutorial (facebook.github.io/react/docs/tutorial.html) I tried to include Flux with browserify, but browser says, that Dispatcher is not found :(

@Matt Styles 2016-02-22 08:44:27

The syntax I used was ES2016 module syntax which requires transpilation (I use Babel, but there are others, the babelify transform can be used with browserify), it transpiles to var Dispatcher = require( 'flux' ).Dispatcher

Related Questions

Sponsored Content

31 Answered Questions

[SOLVED] What is the difference between state and props in React?

  • 2015-01-16 19:28:27
  • skaterdav85
  • 154857 View
  • 425 Score
  • 31 Answer
  • Tags:   javascript reactjs

57 Answered Questions

[SOLVED] How do I include a JavaScript file in another JavaScript file?

3 Answered Questions

58 Answered Questions

[SOLVED] How do I redirect to another webpage?

79 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5829082 View
  • 7268 Score
  • 79 Answer
  • Tags:   javascript arrays

35 Answered Questions

[SOLVED] How do I return the response from an asynchronous call?

54 Answered Questions

[SOLVED] How do I check if an element is hidden in jQuery?

38 Answered Questions

[SOLVED] How do I remove a property from a JavaScript object?

86 Answered Questions

[SOLVED] How do JavaScript closures work?

8 Answered Questions

[SOLVED] Why use Redux over Facebook Flux?

Sponsored Content