I want to pass an item id from either a Child component or grandchild component, but cannot figure out how to do so. Other examples I have looked at show using the arrow function to achieve this, but for whatever reason my function is not getting called.
I have the following in Parent.js
:
chosenItem(id){
console.log("CHOSEN ITEM SELECTED")
this.setState({
chosen_item: id
})
}
and in the Parent.js render function:
<Child objects={objects} chosenItem={() => this.chosenItem()} />
Then in my Child.js
I have:
items = this.props.objects.items.map(item => {
return (
<ClickableTextComponent
key={item.id}
text={item.label}
onClick={item =>this.props.chosenItem(item.id)}
/>
)
})
In my Child.js render function I have:
{items}
I also wasn't sure whether the actual click event should go inside of the Child.js or the ClickableTextComponent. Or does it really matter? Currently I have placed it in the Child.js component as seen above.
What am I doing wrong? How can I modify my code so that the function gets called? I have read a bit about currying to prevent a function from being recreated multiple times. Is that necessary in this case? If so, where and how should I be implementing it. In my Parent or Child components?
Update
I was previously trying to get the onClick to work from Child.js, but as it needs to be attached to a div I have moved it to ClickableTextComponent (the grandchild component).
One issue with ClickableTextComponent
is that I want to be able to set the state when the component is clicked so that I can turn the component a different colour. Because of that I am needing to use a function to then call the chosenItem function. So here is what I have in my `ClickableTextComponent.js':
handleClick(){
this.setState({
text_state: "clicked"
})
this.props.chosenItem()
}
In the render I then have:
<div
onClick={this.handleClick.bind(this)}
onMouseOver={this.changeTextState.bind(this, "hover")}
onMouseOut={this.changeTextState.bind(this, "default")}
>{this.props.text}</div>
New Error
Based on the above changes, I am now getting this.props.chosenItem is not a function
. However, I cannot figure out why it is giving me this error. I can see the function name when I display this.props
to the console. What am I doing wrong?
The answer given by Kevin He holds true. But there is one problem with that solution.
<Child objects={objects} chosenItem={(x) => this.chosenItem(x)} />
When you do such, every time your parent is rerendered. It will create a new instance of the function. And, your child component also rerenders because It sees the props
changing.
Best solution is:
<Child objects={objects} chosenItem={this.chosenItem} />
Update:
Now, it seems to make sense.
The problem is again with ClickableTextComponent
.
Here is the update ClickableTextComponent
which works.
https://codesandbox.io/s/73x6mnr8k0
The main problem:
items = this.props.objects.items.map(item => {
return (
<ClickableTextComponent
key={item.id}
text={item.label}
onClick={item =>this.props.chosenItem(item.id)}
/>
)
})
//
// Here you made a function (item) => this.props.choseItem(item.id)
// That means when you call that function you should call like this
// i.e. passing parameter needed for the function
//
handleClick(){
this.setState({
text_state: "clicked"
})
this.props.chosenItem(item)
}
//
// But do you do not have the item in the children
// Parent should be changed as below
//
items = this.props.objects.items.map(item => {
return (
<ClickableTextComponent
key={item.id}
text={item.label}
onClick={() =>this.props.chosenItem(item.id)}
/>
)
})
//
// Now you made a fuction () => this.props.chosenItem(item.id)
// The main difference being you are not taking a item as parameter
// item will be taken from outer scope that means, item from map
//
//
// Another solution can be
//
items = this.props.objects.items.map(item => {
return (
<ClickableTextComponent
key={item.id}
id={item.id}
text={item.label}
onClick={this.props.chosenItem}
/>
)
})
// And in ClickableTextComponent
handleClick(){
this.setState({
text_state: "clicked"
})
this.props.chosenItem(this.props.id)
}
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments