[英]Passing a function through three levels of components (i.e. calling a function from a grandchild component)
I want to pass an item id from either a Child component or grandchild component, but cannot figure out how to do so. 我想从子组件或孙组件传递项ID,但无法弄清楚如何这样做。 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
: 我在Parent.js
有以下Parent.js
:
chosenItem(id){
console.log("CHOSEN ITEM SELECTED")
this.setState({
chosen_item: id
})
}
and in the Parent.js render function: 并在Parent.js渲染函数中:
<Child objects={objects} chosenItem={() => this.chosenItem()} />
Then in my Child.js
I have: 然后在我的Child.js
我有:
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: 在我的Child.js渲染功能中,我有:
{items}
I also wasn't sure whether the actual click event should go inside of the Child.js or the ClickableTextComponent. 我也不确定实际的click事件是否应该进入Child.js或ClickableTextComponent。 Or does it really matter? 或者它真的重要吗? Currently I have placed it in the Child.js component as seen above. 目前我将它放在Child.js组件中,如上所示。
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. 我已经阅读了一些关于currying的内容,以防止多次重新创建函数。 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). 我以前试图让onClick从Child.js开始工作,但由于它需要附加到div我已经将它移动到ClickableTextComponent(孙子组件)。
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. ClickableTextComponent
一个问题是我希望能够在单击组件时设置状态,以便我可以将组件转换为不同的颜色。 Because of that I am needing to use a function to then call the chosenItem function. 因此,我需要使用函数然后调用selectedItem函数。 So here is what I have in my `ClickableTextComponent.js': 所以这就是我在`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
. 基于以上的变化,我现在得到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. 当我向控制台显示this.props
时,我可以看到函数名称。 What am I doing wrong? 我究竟做错了什么?
The answer given by Kevin He holds true. Kevin He给出的答案是正确的。 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. 并且,您的孩子组件也会重新渲染,因为它会看到props
变化。
Best solution is: 最佳解决方案是:
<Child objects={objects} chosenItem={this.chosenItem} />
Update: 更新:
Now, it seems to make sense. 现在,它似乎有道理。
The problem is again with ClickableTextComponent
. 问题再次出现在ClickableTextComponent
。
Here is the update ClickableTextComponent
which works. 这是更新的ClickableTextComponent
。
https://codesandbox.io/s/73x6mnr8k0 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)
}
You can do this: 你可以这样做:
<Child objects={objects} chosenItem={(x) => this.chosenItem(x)} />
Note that chosenItem
is a function, then whenever it's called with item.id
, it will take call the function this.chosenItem
at the parent element. 请注意, chosenItem
是一个函数,然后无论何时使用item.id
调用它,它都会在父元素上调用函数this.chosenItem
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.