Hi I would like to pass data from same child to parent component multiple times.
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
stateVariabes:null
};
// callback from parent
this.props.onSelect(this.state);
}
handleChange(event) {
const value = event.target.value;
this.setState(
{
stateVariabes: value
},
function() {
console.log(this.state);
// callback from parent
this.props.onSelect(this.state);
}
);
}
}
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
childOne: null,
childList: [],
childOther: null
};
}
childCallbackFunction = childData => {
// which child state shall I set here
this.setState({ weekDay: childData });
};
render() {
return (
<div className="App">
<ChildComponent onSelect={this.childCallbackFunction} />
<ChildComponent onSelect={this.childCallbackFunction} />
<ChildComponent onSelect={this.childCallbackFunction} />
<ChildComponent onSelect={this.childCallbackFunction} />
</div>
);
}
}
When I use only of one the ChildComponent the update of state from child to parent works as expected but when I have multiple ChildComponent inside render of Parent the state update does not happen.
Can someone suggest whats the right way to achieve the task?
When using Class components, you need to bind your methods. From React documentation:
In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
So, in your case, your ChildComponent should have a
this.handleChange = this.handleChange.bind(this);
You should also remove this from your constructor, since it is calling your callback on initialization:
// callback from parent
this.props.onSelect(this.state);
Here is a working example: https://codesandbox.io/s/intelligent-night-xlhzj
More information in this link.
This is how it should do it.
child=>
class ChildCom extends Component {
constructor(props) {
super(props);
this.state = {
stateVariabes: null
};
}
componentDidMount() {
this.onSelect()
}
onSelect = () => {
const value = 'some value coming from your event';
this.props.trigger(value);
};
Parent=>
class ParentCom extends Component {
constructor(props) {
super(props);
this.state = {
childOne: null,
childList: [],
childOther: null,
};
}
childCallbackFunction = childData => {
// you can do anything with your child component values here
console.log('child value: ', childData)
};
render() {
return (
<div className='App'>
<ChildCom trigger={this.childCallbackFunction} />
<ChildCom trigger={this.childCallbackFunction} />
<ChildCom trigger={this.childCallbackFunction} />
<ChildCom trigger={this.childCallbackFunction} />
</div>
Related
I have a parent component
class ParentComponent extends React.PureComponent {
render(){
return(
//IN HERE I'm calling child parent
<ChildComponent/>
)
}
}
class ChildComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sample: '',
};
}
how can I get the sample state to the parent component?
So at the Parent Component make a method which receives value in return.
StateValue = (value) =>{
console.log(value);
}
Pass this method as props to the child component.
<ChildComponent method={this.StateValue}/>
At the child component Pass the state value to the method props received in step 2.
constructor(props) {
super(props);
this.state = {
sample: 'hi',
};
}
render(){
this.props.method(this.state.sample)
return(
<></>
)
You will get your state value in StateValue Method from the props in your parent component.
Try this:
class ParentComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sample: '',
};
}
render(){
return(
<ChildComponent sample={this.state.sample} setState={(sample) => this.setState({ sample })} />
)
}
}
class ChildComponent extends React.PureComponent {
// you can now call this.props.setState(value); to set parent component state.
// and access the sample state: this.props.sample;
}
One option is to specify a callback as a prop. Like this:
class ParentComponent extends React.PureComponent {
onSample = (sample) => {
// handle sample
}
render(){
return(
//IN HERE I'm calling child parent
<ChildComponent
callback={this.onSample}
/>
)
}
}
class ChildComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sample: '',
};
this.onSample = props.callback
// call later on via this.onSample(<sample>);
}
So I started converting my application from ES2015 to ES6 which uses React.
I have a parent class and a child class like so,
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
code: ''
};
}
setCodeChange(newCode) {
this.setState({code: newCode});
}
login() {
if (this.state.code == "") {
// Some functionality
}
}
render() {
return (
<div>
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
</div>
);
}
}
Child class,
export default class Child extends Component {
constructor(props) {
super(props);
}
handleCodeChange(e) {
this.props.onCodeChange(e.target.value);
}
login() {
this.props.onLogin();
}
render() {
return (
<div>
<input name="code" onChange={this.handleCodeChange.bind(this)}/>
</div>
<button id="login" onClick={this.login.bind(this)}>
);
}
}
Child.propTypes = {
onCodeChange: React.PropTypes.func,
onLogin: React.PropTypes.func
};
However this causes the following error,
this.state is undefined
It refers to,
if (this.state.code == "") {
// Some functionality
}
Any idea what could be causing this ?
You can use arrow function to bind you functions. You need to bind you functions both in child as well as parent components.
Parent:
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
code: ''
};
}
setCodeChange = (newCode) => {
this.setState({code: newCode});
}
login = () => {
if (this.state.code == "") {
// Some functionality
}
}
render() {
return (
<div>
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
</div>
);
}
}
Child
export default class Child extends Component {
constructor(props) {
super(props);
}
handleCodeChange = (e) => {
this.props.onCodeChange(e.target.value);
}
login = () => {
this.props.onLogin();
}
render() {
return (
<div>
<input name="code" onChange={this.handleCodeChange}/>
</div>
<button id="login" onClick={this.login}>
);
}
}
Child.propTypes = {
onCodeChange: React.PropTypes.func,
onLogin: React.PropTypes.func
};
There are other ways to bind the functions as well such as the one you are using but you need to do that for parent component too as <Child onCodeChange={this.setCodeChange.bind(this)} onLogin={this.login.bind(this)} />
or you can specify binding in the constructor as
Parent:
constructor(props) {
super(props);
this.state = {
code: ''
};
this.setCodeChange = this.setCodeChange.bind(this);
this.login = this.login.bind(this);
}
Child
constructor(props) {
super(props);
this.handleCodeChange = this.handleCodeChange.bind(this);
this.login = this.login.bind(this);
}
I agree with all different solutions given by #Shubham Kathri except direct binding in render.
You are not recommended to bind your functions directly in render. You are recommended to bind it in constructor always because if you do binding directly in render then whenever your component renders Webpack will create a new function/object in bundled file thus the Webpack bundle file size grows. For many reasons your component re-renders eg: doing setState but if you place it in constructor it gets called called only once.
The below implementation is not recommended
<Child onCodeChange={this.setCodeChange.bind(this)} onLogin={this.login.bind(this)} />
Do it in constructor always and use the ref wherever required
constructor(props){
super(props);
this.login = this.login.bind(this);
this.setCodeChange = this.setCodeChange.bind(this);
}
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
If you are using ES6 then manual binding is not required but if you want you can. You can use arrow functions if you want to stay away with scope related issues and manual function/object bindings.
Sorry if there are any typos I am answering in my mobile
So I started converting my application from ES2015 to ES6 which uses React.
I have a parent class and a child class like so,
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
code: ''
};
}
setCodeChange(newCode) {
this.setState({code: newCode});
}
login() {
if (this.state.code == "") {
// Some functionality
}
}
render() {
return (
<div>
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
</div>
);
}
}
Child class,
export default class Child extends Component {
constructor(props) {
super(props);
}
handleCodeChange(e) {
this.props.onCodeChange(e.target.value);
}
login() {
this.props.onLogin();
}
render() {
return (
<div>
<input name="code" onChange={this.handleCodeChange.bind(this)}/>
</div>
<button id="login" onClick={this.login.bind(this)}>
);
}
}
Child.propTypes = {
onCodeChange: React.PropTypes.func,
onLogin: React.PropTypes.func
};
However this causes the following error,
this.state is undefined
It refers to,
if (this.state.code == "") {
// Some functionality
}
Any idea what could be causing this ?
You can use arrow function to bind you functions. You need to bind you functions both in child as well as parent components.
Parent:
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
code: ''
};
}
setCodeChange = (newCode) => {
this.setState({code: newCode});
}
login = () => {
if (this.state.code == "") {
// Some functionality
}
}
render() {
return (
<div>
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
</div>
);
}
}
Child
export default class Child extends Component {
constructor(props) {
super(props);
}
handleCodeChange = (e) => {
this.props.onCodeChange(e.target.value);
}
login = () => {
this.props.onLogin();
}
render() {
return (
<div>
<input name="code" onChange={this.handleCodeChange}/>
</div>
<button id="login" onClick={this.login}>
);
}
}
Child.propTypes = {
onCodeChange: React.PropTypes.func,
onLogin: React.PropTypes.func
};
There are other ways to bind the functions as well such as the one you are using but you need to do that for parent component too as <Child onCodeChange={this.setCodeChange.bind(this)} onLogin={this.login.bind(this)} />
or you can specify binding in the constructor as
Parent:
constructor(props) {
super(props);
this.state = {
code: ''
};
this.setCodeChange = this.setCodeChange.bind(this);
this.login = this.login.bind(this);
}
Child
constructor(props) {
super(props);
this.handleCodeChange = this.handleCodeChange.bind(this);
this.login = this.login.bind(this);
}
I agree with all different solutions given by #Shubham Kathri except direct binding in render.
You are not recommended to bind your functions directly in render. You are recommended to bind it in constructor always because if you do binding directly in render then whenever your component renders Webpack will create a new function/object in bundled file thus the Webpack bundle file size grows. For many reasons your component re-renders eg: doing setState but if you place it in constructor it gets called called only once.
The below implementation is not recommended
<Child onCodeChange={this.setCodeChange.bind(this)} onLogin={this.login.bind(this)} />
Do it in constructor always and use the ref wherever required
constructor(props){
super(props);
this.login = this.login.bind(this);
this.setCodeChange = this.setCodeChange.bind(this);
}
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
If you are using ES6 then manual binding is not required but if you want you can. You can use arrow functions if you want to stay away with scope related issues and manual function/object bindings.
Sorry if there are any typos I am answering in my mobile
I want to update the value of 'change_color' in the second class and automatically render it in the first class when the value gets changed.
Assume, 'Second' component as the child of the 'First' component.
Solved it. Code is edited and it is the answer.
class First extends Component {
constructor() {
super();
this.state = {
change_color: false
}
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState({
change_color: true
})
}
render() {
console.log(this.state.change_color);
return(<div><Second colorChange={this.handleChange} /></div>)
}
}
class Second extends Component {
constructor() {
super();
}
render() {
return(<div><button onClick={this.props.colorChange} /></div>)
}
}
Maybe you can try this, just make a container component, and set the value you want to change into a state of the container component, add a method to change the state value, then, you can use "this.props.handleColorChange" to call the method of the parent component in children components.
class ParentComponent extends Component {
constructor() {
super();
this.state = {
change_color: false
}
}
handleColorChange= () => {
const {change_color} = this.state;
this.setState = {
change_color: !change_color
}
}
render() {
const {change_color} = this.state,
{handleColorChange} = this;
return (
<div>
<ChildComponent1
color={change_color}
handleColorChange={handleColorChange}
/>
<ChildComponent2
color={change_color}
handleColorChange={handleColorChange}
/>
</div>
);
}
}
class ChildComponent1 extends Component {
constructor() {
super();
}
render() {
const {color} = this.props;
return(
<span>now, the color is {color}</span>
)
}
}
class ChildComponent2 extends Component {
constructor() {
super();
}
const {handleColorChange} = this.props;
return(
<button onClick={handleColorChange}>click to change color</button>
)
}
What you need to do is lifting up the state. Create a new component that has a state with the colour and the change colour function. Then pass to first and second componentes the corresponding properties as props and inside of them call the function to change the colour. Does it makes sense?
So I have one root component and two child components. I have trying to get one child to call a method that is up in in the root component and update the state up in the root component, and pass the updated down to the other component, but I am getting the following error.
What could be the issue?
warning.js?8a56:36 Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the firstChild component.
Here is the code:
firstChild.js
export default class firstChild extends React.Component {
constructor(props) {
super(props);
this.state = {
nameText: '',
}
}
nameChange(event) {
this.setState({
nameText: event.target.value,
})
}
submitClick() {
var nameText = this.state.nameText;
this.props.saveName(nameText)
this.setState({nameText: ''});
}
render() {
var st = this.state;
var pr = this.props;
return (
<input
placeholder='Enter Name'
onChange={this.nameChange.bind(this)}
value={this.state.nameText}
/>
<button
onClick={this.submitClick.bind(this)}
/>
And in root component, App.js:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
submitSuccess: false
}
}
saveName(nameText) {
this.setState({submitSuccess: true});
}
render() {
var props = {};
props.submitSuccess = this.state.submitSuccess;
return (
<div>
<firstChild
saveName={this.saveName.bind(this)}
/>
{React.Children.map(this.props.children, function(child) {
return React.cloneElement(child, props);
})}
</div>
)
}
}
And my secondChild.js:
export default class secondChild extends React.Component {
static propTypes = {
submitSuccess: React.PropTypes.bool.isRequired,
}
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div>
{this.props.submitSuccess}
</div>
)
}
}
Fisrt, rename all your React components as Camel Case like this.
class firstChild ... --> class FristChild
<fristChild> --> <FristChild>
Second, in your FirstChild render method, you should wrap your elements into an enclosing tag like this:
class FirstChild extends Component {
render(){
return (
<div>
<input ... />
<button ... />
</div>
)
}
}
Third, when you use cloneElement upon this.props.children, you should use Proptypes.<type> in your secondChildren instead of Propstypes.<type>.isRequired. Check it here to see why.
class SecondChild extends Component {
static propTypes = {
submitSuccess: React.PropTypes.bool, // remove isRequired
}
}
Regardless all above, I have tested your code and it works fine.
You can try and use componentWillUnmount lifecycle function in order to check when the component is unmounted.
You can also use a flag to signal that the component is unmounted before setting the state:
saveName(nameText) {
if (!this.isUnmounted){
this.setState({submitSuccess: true});
}
}
componentWillUnmount() {
this.isUnmounted = true;
}