Событие щелчка не обновляется в React / D3 при обновлении данных - PullRequest
1 голос
/ 18 апреля 2019

У меня есть компонент React, который отображает столбчатую диаграмму D3, где столбцы можно нажимать. Он работает, как и ожидалось, пока родительское состояние не будет обновлено. Стержни обновляются правильно, но события щелчков на панелях все еще привязаны к предыдущим данным Я не уверен, что я что-то не так делаю в React, D3 или обоих. Любая помощь приветствуется.

const DATA1 = [{"value":1}, {"value":1}]

const DATA2 = [{"value":3}, {"value":3}, {"value":3}, {"value":2}, {"value":2}]

const CLICK = 'chartClick'

function handleClick(data, i, els) {
  const element = els[i]

  const event = new Event(CLICK, {bubbles: true, detail: data})

  return element.dispatchEvent(event)
}

class D3Chart {
  constructor(selector) {
    this.svg = d3.select(selector).append('svg')
  }

  draw(data) {
    const xScale = d3.scaleLinear()
      .domain([0, d3.max(data.map(i => i.value))])
      .range([0, 500])

    const barGroups = this.svg.selectAll('.barGroup').data(data)

    const barGroupsEnter = barGroups.enter().append('g')
      .attr('class', 'barGroup')
      .attr('transform', (d, i) => {
        const y = (i * 25)

        return `translate(0, ${y})`
      })

    barGroupsEnter.append('rect')
      .attr('class', 'bar')
      .attr('height', 20)
      .attr('width', d => xScale(d.value))
      .on('click', handleClick)

    barGroups.exit().remove()
  }
}


class Chart extends React.Component {
  chartRef = React.createRef()

  componentDidMount() {
    const {data, onClick} = this.props

    this.chartRef.current.addEventListener(CLICK, onClick)

    this.chart = new D3Chart(this.chartRef.current)

    this.chart.draw(data)
  }

  shouldComponentUpdate(nextProps) {
    const {data} = this.props

    return !_.isEqual(data, nextProps.data)
  }

  componentDidUpdate() {
    const {data} = this.props

    this.chart.draw(data)
  }

  render() {
    return <div ref={this.chartRef}></div>
  }
}


class App extends React.Component {
  state = {data: DATA1}

  handleButtonClick = () => this.setState({data: DATA2})

  handleChartClick = (data, event) => console.log('data length on click', data.length)

  render() {
    const {data} = this.state

    console.log('data length on render', data.length)

    return (
      <React.Fragment>
        <button onClick={this.handleButtonClick}>Update Data</button>
        <Chart data={data} onClick={(event) => this.handleChartClick(data, event)} />
      </React.Fragment>
    )
  }
}

ReactDOM.render(<App />, document.querySelector('.root'))

Вывод при первом рендере / клике:

"data length on render" 2
"data length on click" 2

Выход после обновления данных:

"data length on render" 5
"data length on click" 2

Я ожидаю, что последний будет:

"data length on render" 5
"data length on click" 5

Пример Codepen здесь: https://codepen.io/bohmanart/pen/QPQJdX

1 Ответ

0 голосов
/ 18 апреля 2019

Вы можете попробовать приведенное ниже решение, изменить событие onclick внутри диаграммы на this.chartRef.current.addEventListener(CLICK, ()=>onClick(this.props.data.length);), изменить реквизиты onClick на диаграмме на onClick={this.handleChartClick}, а затем изменить клик на ручке диаграммы на handleChartClick = (data) =>{ console.log('data length on click', data);}

Я не уверен в случае использования того, почему вы хотите передать данные из компонента Chart через handleChartClick, когда он уже доступен в состоянии класса приложения. Вы можете просто использовать this.state.data.length в handleChartClick

...