在 React 中单击时,如何防止所有手风琴组件被切换?

How can I prevent all of my accodion components being toggled when clicked in React?

我创建了一个自定义 Accordion 组件,它又由两个 child 组件组成,分别称为 AccordionTitleAccordionContent:

AccordionTitle 组件有一个按钮。单击时,AccordionContent 部分将其样式从 display:none 切换到 block,然后再次单击时返回。

AccordionTitle.js

class AccordionTitle extends Component {
  constructor() {
    super();
    this.show = false;
  }

  toggle() {
    this.show = !this.show;
    if (this.props.onToggled) this.props.onToggled(this.show);
  }

  render() {
    return (
      <div style={this.props.style}>
        <Button onClick={e => this.toggle(e)} />
        {this.props.children}
      </div>
    );
  }
}

export default AccordionTitle;

AccordionContent.js

class AccordionContent extends Component {
  render() {
    let style = this.props.style ? this.props.style : {};
    style = JSON.parse(JSON.stringify(style));
    style.display = this.props.show ? 'block' : 'none';

    return (
      <div style={style}>
        {this.props.children}
      </div>
    );
  }
}

export default AccordionContent;

此外,我使用以下 parent 组件:

Accordion.js

class Accordion extends Component {
  render() {
    return (
      <div>
        {this.props.children}
      </div>
    );
  }
}

Accordion.Title = AccordionTitle;
Accordion.Content = AccordionContent;

export default Accordion;

现在,当我使用手风琴组件时,我可能需要连续使用多个手风琴,如下所示:

产品Accordion.js

import React, { Component } from 'react';
import Accordion from '../Accordion/Accordion';

class ProductAccordion extends Component {
  constructor() {
    super();
    this.state = {
      show: false,
    };
  }

  toggled() {
    this.setState({
      show: !this.state.show,
    });
  }

  render() {
    this.productsJsx = [];
    const products = this.props.products;

    for (let i = 0; i < products.length; i += 1) {
      this.productsJsx.push(
        <Accordion.Title onToggled={e => this.toggled(e, this)}>
          {products[i].name}
          <img src="{products[i].imgsrc}" />
        </Accordion.Title>,
        <Accordion.Content show={this.state.show}>
          {products[i].name}<br />
          {products[i].grossprice} {products[i].currency}<br />
          <hr />
        </Accordion.Content>,
      );
    }

    return (
      <Accordion style={styles.container}>
        {this.productsJsx}
      </Accordion>
    );
  }
}

export default ProductAccordion;

如您所见,我正在从 Accordion.Title 获取 toggled 事件,并通过 [=24= 将其绑定到 Accordion.Content 的属性 show ]方法。

现在,只要只有一种产品,它就可以正常工作,但如果有更多产品,单击按钮将切换所有 AccordionContent 个实例。

如何更改此设置,以便仅切换属于包含单击按钮的标题的 content-part?

我也觉得组件 Accordion 应该通过允许 Accordion.Titletoggled 事件直接委托给来处理这个(而不是 ProductAccordion)它的兄弟 Accordion.Content。我怎样才能做到这一点?

我建议将未清项目的索引存储在状态中,而不是布尔值。然后在您的渲染中,show={this.state.show} 将类似于 show={this.state.show === i}.

完整示例:

import React, { Component } from 'react';
import Accordion from '../Accordion/Accordion';

class ProductAccordion extends Component {
  constructor() {
    super();
    this.state = {
      show: null,
    };
  }

  toggled(event, ind) {
    const index = this.state.index;
    this.setState({ show:ind === index ? null : ind });
  }

  render() {
    this.productsJsx = [];
    const products = this.props.products;

    for (let i = 0; i < products.length; i += 1) {
      this.productsJsx.push(
        <Accordion.Title onToggled={e => this.toggled(e, i)}>
          {products[i].name}
          <img src="{products[i].imgsrc}" />
        </Accordion.Title>,
        <Accordion.Content show={this.state.show === i}>
          {products[i].name}<br />
          {products[i].grossprice} {products[i].currency}<br />
          <hr />
        </Accordion.Content>,
      );
    }

    return (
      <Accordion style={styles.container}>
        {this.productsJsx}
      </Accordion>
    );
  }
}

export default ProductAccordion;

还有这个

class AccordionTitle extends Component {
  constructor() {
    super();
  }


  render() {
    return (
      <div style={this.props.style}>
        <Button onClick={this.props.onToggled} />
        {this.props.children}
      </div>
    );
  }
}

export default AccordionTitle;