reactjs - 如何从父组件调用子组件中的事件处理程序或方法?
问题描述
我正在尝试在 Material-UI 文档中实现类似于 Floating Action Button (FAB) 的东西:
https://material-ui.com/demos/buttons/#floating-action-buttons
他们有类似的东西:
<SwipeableViews>
<TabContainer dir={theme.direction}>Item One</TabContainer>
<TabContainer dir={theme.direction}>Item Two</TabContainer>
<TabContainer dir={theme.direction}>Item Three</TabContainer>
</SwipeableViews>
{
fabs.map((fab, index) => (
<Zoom>
<Fab>{fab.icon}</Fab>
</Zoom>
));
}
我有类似的东西:
<SwipeableViews>
<TabContainer dir={theme.direction}>
<ListOfThingsComponent />
</TabContainer>
<TabContainer dir={theme.direction}>Item Two</TabContainer>
<TabContainer dir={theme.direction}>Item Three</TabContainer>
</SwipeableViews>
{
fabs.map((fab, index) => (
<Zoom>
<Fab onClick={ListOfThingsComponent.Add???}>
Add Item to List Component
</Fab>
</Zoom>
));
}
我ListOfThingsComponent
最初有一个Add
按钮,效果很好。但我想像他们在文档中那样遵循 FAB 方法。为了做到这一点,添加按钮将驻留在子组件之外。那么如何从父组件中获取一个按钮来调用子组件的 Add 方法呢?
我不确定如何实际实现 Add Item to List click 事件处理程序,因为我的列表组件位于选项卡内,而 FAB 位于整个选项卡结构之外。
据我所知,我可以:
- 找到一种方法来连接父/子以通过各个级别传递事件处理程序(例如,如何将事件处理程序传递给 React 中的子组件)
- 找到一种方法来更好地组合组件/层次结构以将责任放在正确的级别(例如,删除组件并将其放在同一个文件中,并
this
在范围内使用功能组件?)
我见过人们使用ref
,但这只是感觉很hacky。我想知道它应该如何在 React 中完成。如果该示例更进一步并显示 FAB 的事件处理应该驻留在哪里,那就太好了。
提前谢谢,一如既往,我会发布我最终做的事情
解决方案
这取决于您期望点击执行的操作。他们只会改变给定项目的状态,还是会在该层次结构之外执行更改?晶圆厂是否会出现在每个选项卡中,或者您不确定?
我认为在大多数情况下,你最好做你以前做的事情。为每个 Tab 编写一个 CustomComponent 并让它自己处理 FAB。这可能是一种不好的方法的唯一情况是,如果您事先知道 FAB 的回调将在 CustomComponent 层次结构中进行更改,因为在这种情况下,从长远来看,您最终可能会遇到回调混乱(仍然,没有任何全局状态管理无法解决的问题)。
编辑后编辑:在 React 中使用按钮调用子组件内部的函数可以说是不可能的(不借助 Refs 或其他完全避免 React 的机制),因为它的数据流是单向的。该函数必须在某个共同的地方,在这种情况下,在安装按钮的组件和 ListOfThings 组件中。该按钮将调用该方法,该方法将更改“父”组件中的状态,并且新状态通过道具传递给 ListOfThings 组件:
export default class Parent extends Component {
state = {
list: []
};
clickHandler = () => {
// Update state however you need
this.setState({
list: [...this.state.list, 'newItem']
});
}
render() {
return (
<div>
<SwipeableViews>
<TabContainer dir={theme.direction}>
<ListOfThingsComponent list={this.state.list /* Passing the state as prop */}/>
</TabContainer>
<TabContainer dir={theme.direction}>Item Two</TabContainer>
<TabContainer dir={theme.direction}>Item Three</TabContainer>
</SwipeableViews>
{
fabs.map((fab, index) => (
<Zoom>
<Fab onClick={this.clickHandler /* Passing the click callback */}>
Add Item to List Component
</Fab>
</Zoom>
))
}
</div>
)
}
}
如果你真的需要你的层次结构保持这样,你必须使用这种方法或某种形式的 ListOfThingsComponent 可以读取的全局状态管理。
推荐阅读
- javascript - 为什么输出结果不一样?
- typescript - 如何使 TypeScript 缩小父对象的类型?
- c - 使用和不使用条件变量的两个线程有什么区别?
- python - 向 displot 中的所有子图添加行(Seaborn)
- sql - 如何在oracle中查找json数组中存在的行数?
- reactjs - 在 React-Flow 库中,我们可以只获取叶节点吗?
- awk - 如何使用`md5sum`处理`awk`的`$1`?
- python - Kafka 消息密钥为无
- arrays - 对线性回归建模,输入向量
- django - 我的 django 表单没有在管理面板中保存输入