【问题标题】:React - Call parent method from within child componentReact - 从子组件中调用父方法
【发布时间】:2018-07-20 11:59:23
【问题描述】:

为这个菜鸟问题道歉,但我对 React 相当陌生。我在这里看到了一些与我所坚持的问题类似的问题,但我相信我的要求略有不同。

我正在创建一个 Accordion 组件,它是 AccordionItem 子组件的父组件。我为每个 AccordionItem 赋予了它自己的状态,以跟踪该项目是处于打开状态还是关闭状态。这很好用,我现在有一个可以工作的手风琴,当您单击项目的标题时,每个项目都可以打开或关闭。

但是我现在想添加功能,如果 AccordionItem 已经处于打开状态,它将在选择另一个 AccordionItem 时关闭。我相信我的 Accordion.js 中需要一个状态数组或对象来跟踪当前选择的 AccordionItems,然后每次点击都会更新。

我正在努力研究如何将父方法传递给子组件。

我的 App.js 目前如下所示:

class App extends Component {
  render() {
    return (
      <Accordion>
        <AccordionItem title="Question One Title" itemid="question1" openOnLoad onChange={this.updateSelectedItems}>
          <p>here is some text 1</p>
        </AccordionItem>
        <AccordionItem title="Question Two Title" itemid="question2" onChange={this.updateSelectedItems}>
          <p>here is some text 2</p>
        </AccordionItem>
        <AccordionItem title="Question Three Title" itemid="question3" onChange={this.updateSelectedItems}>
          <p>here is some text 3</p>
        </AccordionItem>
      </Accordion>
    );
  }

}

我在网上看到的所有示例都显示父组件有一个道具,该道具将所选父方法的引用传递给子组件。但是,因为我的 AccordionItems 是在 App.js 中定义的,而不是 Accordion.js,所以 this.updateSelectedItems 在此文件中不存在。

我不想将 AccordionItems 移动到 Accordion 中,因为这样每个 Accordion 都会有相同的数据。

想法?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    我认为这篇文章https://reactjs.org/docs/composition-vs-inheritance.html 可能会对您有所帮助。

    在您的情况下,您可能会在 Accordion 组件的 render 方法中执行类似的操作:

    render() {
      return (
        <div>
        {
          this.props.children.map(
            child => {
              child.passedMethod = this.updateSelectedItems;
              return child;
            }
          )
        }
        </div>
      );
    }
    

    【讨论】:

    • 是的,这看起来很有希望。那么在 App.js 中定义 updateSelectedItems 并通过 props 将其传递给 Accordion,然后再将其传递给 AccordionItems?
    • 不,我上面展示的是Accordion的render方法,所以this.updateSelectedItems是指Accordion。我认为您在这里缺少的是,当您将一些组件放入 jsx 代码中的另一个组件中时,您实际上所做的是将它们作为 children 属性传递给包装器。因此,您可以在定义包装器的代码中操作子代,即使它们不为人所知,而是传递到其他地方。您所要做的就是在包装器组件中将它们称为this.props.children
    • 作为免责声明,上面的代码是一个可能实现的想法,我没有测试它但应该可以工作
    【解决方案2】:

    如果 Accordion 正在跟踪 AccordionItem 组件,那么您应该让 Accordion 处理 AccordionItems 的呈现。

    App.js

    class App extends Component {
      render() {
        return
          <Accordion />;
      }
    

    手风琴.js

    updateItems = () => ...
    
    render() {
      return (
        <div>
                <AccordionItem title="Question One Title" itemid="question1" openOnLoad onChange={this.updateSelectedItems}>
                  <p>here is some text 1</p>
                </AccordionItem>
                <AccordionItem title="Question Two Title" itemid="question2" onChange={this.updateSelectedItems}>
                  <p>here is some text 2</p>
                </AccordionItem>
                <AccordionItem title="Question Three Title" itemid="question3" onChange={this.updateSelectedItems}>
                  <p>here is some text 3</p>
                </AccordionItem>
        </div>
      );
    }
    

    【讨论】:

    • 我确实明确表示我知道我可以做到,但我不想因为 Accordion 组件的每个实例都会有相同的项目
    【解决方案3】:

    遵循 Reactjs 基础知识,在 Parent (Accordion) 中维护您的状态并将该状态传递给所有子 (AccordionItem)。此外,您需要通过一个事件处理程序(将更新父状态),在选择任何子(手持人)时会调用。

    【讨论】:

    【解决方案4】:

    这是我拼凑起来的东西。在这里工作 JSFiddle:https://jsfiddle.net/gkysmsqz/6/

    Accordion 应该保持应该显示手风琴部分的活动索引。您可以克隆每个孩子并在渲染之前为它们添加一些额外的道具(active 和 toggleSection 在下面的示例中):

    class App extends React.Component {
      render() {
        return (
          <Accordion>
            <AccordionItem title="Question One Title" itemid="question1" openOnLoad onChange={this.updateSelectedItems}>
              <p>here is some text 1</p>
            </AccordionItem>
            <AccordionItem title="Question Two Title" itemid="question2" onChange={this.updateSelectedItems}>
              <p>here is some text 2</p>
            </AccordionItem>
            <AccordionItem title="Question Three Title" itemid="question3" onChange={this.updateSelectedItems}>
              <p>here is some text 3</p>
            </AccordionItem>
          </Accordion>
        );
      }
    }
    
    class Accordion extends React.Component {
        state = {
        activeIndex: 0
      };
    
      toggleSection = index => {
        this.setState({
            activeIndex: index
        });
      };
    
        render() {
        const rows = this.props.children.map( (child, i) => {
            return React.cloneElement(child, { active: i === this.state.activeIndex, toggleSection: this.toggleSection.bind(this, i) });
        });
        return (
            <div>
              {rows}
            </div>
        );
      }
    }
    
    const AccordionItem = props => (
      <div>
        <span onClick={props.toggleSection}>{props.title}</span>
        <div className={props.active ? 'active accordion-item' : 'accordion-item'}>
          {props.children}
        </div>
      </div>
    );
    

    【讨论】:

    • @OP 或者在您的情况下,您可以将updateSelectedItems 传递给Accordion,然后像我传递toggleSection 一样将其传递给每个孩子。
    猜你喜欢
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 2017-02-27
    • 2020-09-11
    • 2017-11-24
    • 2020-02-15
    • 2020-10-20
    相关资源
    最近更新 更多