EventPropagation в React аккордеоне - PullRequest
0 голосов
/ 17 мая 2019

Я использую эту библиотеку https://github.com/emilpalsson/react-tiny-accordion, чтобы добавить простой аккордеон в мой реактивный проект.Однако, если я изменю поле формы или нажму кнопку в разделе аккордеона, он также закроет весь раздел, когда я на самом деле хочу оставаться открытым, пока я заполняю этот раздел формы.

Я решил, что кнопкаФункция onClick запускала аккордеон onClick, и я пытался сделать e.stopPropagation() в моих функциях onClick кнопки, но это не имело никакого значения.Я еще не очень хорошо знаю, как реагировать, и код из библиотеки мне немного сложен для понимания (особенно потому, что он использует ссылки, а я их раньше не использовал).Был бы признателен, если бы кто-то мог дать некоторое представление о том, что мне, возможно, нужно изменить или добавить?

Код, используемый для настройки аккордеона:

import React from 'react'

class Accordion extends React.Component {
  constructor(props) {
    super(props)
    const { children, selectedIndex } = this.props
    this.index = typeof props.selectedIndex !== 'undefined' ? props.selectedIndex : -1
    this.nodes = []
    this.state = {
      heights: React.Children.map(
        children,
        (child, index) => (index === selectedIndex ? 'auto' : 0)
      )
    }
  }

  componentWillReceiveProps(props) {
    const { selectedIndex } = props
    if (typeof selectedIndex !== 'undefined' && this.index !== selectedIndex) {
      this.toggle(selectedIndex)
    }
  }

  componentWillUnmount() {
    clearTimeout(this.timeout)
  }

  close(index) {
    setTimeout(() => this.setHeight(index, 0), 50)
  }

  setHeight(index, height, callback) {
    const heights = this.state.heights.slice()
    heights[index] = height
    this.setState({ heights }, callback)
  }

  open(index) {
    clearTimeout(this.timeout)
    this.setHeight(index, this.nodes[index].children[1].children[0].offsetHeight, () => {
      this.timeout = setTimeout(() => this.setHeight(index, 'auto'), this.props.transitionDuration)
    })
  }

  setFixedHeightOnCurrentlyOpenedItem() {
    return new Promise(resolve => {
      if (this.index > -1) {
        this.setHeight(
          this.index,
          this.nodes[this.index].children[1].children[0].offsetHeight,
          resolve
        )
      }
      else {
        resolve()
      }
    })
  }

  toggle(index, click) {
    const { onChange, changeOnClick } = this.props 
    clearTimeout(this.timeout)

    if (click) {
      if (onChange) {
        onChange(index, this.index !== index, this.index !== index ? index : -1)
      }
      if (!changeOnClick) return
    }

    // First, set a fixed height on the currently opened item, for collapse animation to work
    this.setFixedHeightOnCurrentlyOpenedItem().then(() => {
      if (this.index > -1) {
        this.close(this.index)
      }

      if (index > -1 && index !== this.index) {
        this.index = index
        this.open(index)
      }
      else {
        this.index = -1
      }
    })
  }

  render() {
    const { transitionDuration, transitionTimingFunction, className, openClassName } = this.props
    const nodes = React.Children.map(this.props.children, (child, index) => (
      <div
        key={index}
        ref={div => {
          this.nodes[index] = div
        }}
        className={this.index === index ? openClassName : ''}
      >
        <div onClick={() => this.toggle(index, true)}>{child.props['data-header']}</div>
        <div style={{
          overflow: 'hidden',
          transition: `height ${transitionDuration}ms ${transitionTimingFunction}`,
          height: this.state.heights[index] 
        }}>{child}</div>
      </div>
    ))
    return <div className={className}>{nodes}</div>
  }
}

Accordion.defaultProps = {
  transitionDuration: 500,
  transitionTimingFunction: 'ease',
  openClassName: 'open',
  changeOnClick: true
}

export default Accordion

Код моей формы - нажата кнопкаили поле формы, введенное в один из компонентов FormSection, приведет к закрытию аккордеона.


class Form extends Component{
    state = { selectedIndex: 0}

      render(){
        const { 
            handleFormChange, 
            buttonClick,
            handleFormData
        } = this.props;

    return (
        <React.Fragment>
            <h1>Form</h1>
            <form id="form" onChange={handleFormChange}>
                <Accordion className="accordion" selectedIndex={this.state.selectedIndex}>

                    <div className="accordion-item" data-header="Step 1">
                        <FormSection1 buttonClick={buttonClick}/>
                    </div>

                    <div className="accordion-item" data-header="Step 2">
                        <FormSection2 />
                    </div>

                    <div className="accordion-item" data-header="Step 3">
                        <FormSection3 handleFormData={handleFormData} />
                    </div>

                </Accordion>
            </form>
        </React.Fragment>
    ) 
}
}

По сути, все, что я хочу, это чтобы секция аккордеона оставалась открытой, пока я заполняю форму и нажимаю любые кнопки вэтот раздел.Оно должно закрываться, только если я щелкну строку заголовка или следующий раздел формы.

...