如何从父级调用子级组件中的事件处理程序或方法?

时间:2019-03-13 13:41:30

标签: reactjs event-handling components material-ui

我正在尝试实现类似于Material-UI文档中的“浮动操作按钮(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方法?

由于我的列表组件位于选项卡内部,而FAB处于整个选项卡结构之外,因此我不确定如何实际实现“将项目添加到列表”单击事件处理程序。

据我所知:

  1. 找到一种连接父/子的方法,以将事件处理程序传递给各个级别(例如How to pass an event handler to a child component in React
  2. 找到一种更好地组成组件/层次结构的方法,以将职责置于正确的级别(例如,使用功能组件删除组件并将其放入范围为this的同一文件中?)

我已经看到人们使用ref,但这感觉很hacky。我想知道如何在React中完成它们。如果该示例再进一步说明了事件处理应该驻留在FAB上,那将是很好的选择。

像往常一样,提前感谢,我将发布最终的内容

1 个答案:

答案 0 :(得分:1)

这取决于您期望的点击次数。他们会只更改给定项目的状态,还是会在该层次结构之外执行更改?晶圆厂会出现在每个Tab中吗?还是不确定?

在大多数情况下,我认为您最好还是做以前做的事情。为每个选项卡编写一个CustomComponent,并让它自己处理FAB。唯一可能是不好的方法的情况是,如果您事先知道FAB的回调将对CustomComponent层次结构进行修改,那么从长远来看,您可能最终会陷入回调混乱(仍然,全球状态管理无法解决的所有问题。

编辑后编辑:由于在一个子组件内部有一个函数调用按钮,这在React中是不可能做到的(无需借助Ref或其他完全避免React的机制)。单向数据流。该功能必须有共同点,在这种情况下,在安装按钮的组件和ListOfThings组件中。该按钮将调用该方法,该方法将更改“父母”组件中的状态,新状态通过props传递给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可以读取的这种方法或某种形式的全局状态管理。