My structure looks as follows:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
Component 3 s
-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;
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>
)
} }
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 =)
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.
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
If this same scenario is not spread everywhere you can use React's context, specially if you don't want to introduce all the overhead that state management libraries introduce. Plus, it's easier to learn. But be careful, you could overuse it and start writing bad code. Basically you define a Container component (that will hold and keep that piece of state for you) making all the components interested in writing/reading that piece of data its children (not necessarily direct children)
https://reactjs.org/docs/context.html
You could also use plain React properly instead.
<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />
pass doSomethingAbout5 up to Component 1
<Component1>
<Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
<Component5 propThatDependsOn5={this.state.somethingAbout5}/>
<Component1/>
If this a common problem you should starting thinking moving the whole state of the application to someplace else. You have a few options, the most common are:
https://redux.js.org/
https://facebook.github.io/flux/
Basically, instead of managing the application state in your component you send commands when something happens to get the state updated. Components pull the state from this container as well so all the data is centralized. This doesn't mean can't use local state anymore, but that's a more advanced topic.