Reputation: 83
I am trying to bind a method of a parent component to the state of its child component but I'm unable to get the desired result. I checked the value of 'this' in App component and it still points to the App component. Should it not be pointing to the ItemsList component since its being binded to it using bind()? Can someone please point out the mistake I'm making.
import React from 'react';
import {render} from 'react-dom';
class Item extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div> {this.props.value} </div>;
}
}
class ItemList extends React.Component {
constructor(props) {
super(props);
this.state = {
itemArray: ['Work', 'Learn React']
}
this.props.adder.bind(this);
console.log(this.props.adder)
}
render() {
const items = this.state.itemArray.map(el=><Item key={el} value={el} />);
return (
<div>
<h2> To Do List </h2>
<ul>{items}</ul>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
}
addElement (data) {
let items = this.state.ItemList;
items.push(<Item value={data} />);
}
render() {
return (
<div>
<input type="text" ref={input=>this.input=input} />
<input type="button" value="Add" onClick={()=>this.addElement(this.input.value)}/>
<ItemList adder={this.addElement} />
</div>
);
}
}
render(<App />, document.getElementById('root'));
Upvotes: 0
Views: 52
Reputation: 1370
Though what you want is technically possible, this is a much more explicit easy to understand way to do it.
I re-factored your code so that the data flow only goes in one direction, from App
to `Itemimport React from "react";
import { render } from "react-dom";
I also changed Item
and ItemList
to stateless components that take value
and items
as props respectively.
The main change is that App
holds the state instead of ItemList
const Item = ({ value }) => <div>{value}</div>;
const ItemList = ({ items }) => (
<div>
<h2>To Do List</h2>
{items.map(item => <Item key={item} value={item} />)}
</div>
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: ["Work", "Learn React"]
};
}
addElement(value) {
this.setState(state => ({
items: [...state.items, value]
}));
}
render() {
return (
<div>
<input type="text" ref={input => (this.input = input)} />
<input
type="button"
value="Add"
onClick={() => this.addElement(this.input.value)}
/>
<ItemList items={this.state.items} />
</div>
);
}
}
render(<App />, document.querySelector("#root"));
Here is a CodeSandbox with your working app: https://codesandbox.io/s/4r4v0w5o94
Upvotes: 1
Reputation: 15292
Should it not be pointing to the ItemsList component since its being binded to it using bind()?
Well,the step you following in not right one.
In App
Component
You need to store the ItemList
(child) component reference in App(parent
) component.
<ItemList adder={this.addElement} bindChild = {(ref)=>this.itemList = ref}/>
In ItemList
component,
you need to call bindChild
method when ItemList
component mounted.
componentDidMount(){
this.props.bindChild(this);
}
Now, in your App
(parent) component, you have reference for ItemList
(child) component in this.itemList
property.
In App
component, you can use this.itemList
to update state of ItemList
(child) component.
addElement(data) {
let items = this.itemList.state.itemArray;
console.log(items);
const newItem = <Item value={data} />
this.itemList.setState({ itemArray : [...items, newItem]})
}
Please check complete example on codesandbox
Upvotes: 1