React.js 处理第 3 方库安装

React.js handling 3rd party library mounting

我在 React 组件中使用第三方库时发现了一个尴尬的错误。我能够为此 post.

重现人为设计的演示

首先让我解释一下,我正在使用 c3js - 这是一个图表库,并在 componentDidMount() 中呈现它,并在 componentWillUnmount() 中通过正确调用 this.chart.destroy() 将其删除。

错误发生在过滤组件本身时,本质上发生的是组件被正确过滤但位于组件内部的实际图表与第一个图表保持相同,这是非常奇怪的行为.基本上是错误组件内的错误图表!

您可以通过单击 Remove all charts except chart 3 按钮明白我的意思,我已经用 chartid 标记了图表,过滤将正确删除其他图表。

我相当确定这不是我的代码,因为过滤工作正常并更新了视图。您可以验证,因为我已经标记了图表并且它在视图中可见。没有控制台错误,我已验证我的代码有效。

所以我的问题是 - 我们可以使用 c3js 解决这个限制吗,或者这真的是我的代码和我呈现图表的方式的问题。

相关演示:https://jsfiddle.net/69z2wepo/38614/

相关代码:

var data = [
  {
    chartid: 1,
    columns: [
                ['x', 0, 1, 2, 3, 4, 5, 6],
                ['data1', 130, 300, 330, 400, 300, 400, 500],
                ['data2', 390, 230, 200, 150, 100, 130, 210],
                ['data3', 290, 430, 300, 160, 210, 170, 190],
                ['data4', 190, 330, 200, 260, 190, 250, 320]
    ]
  },
  {
    chartid: 2,
    columns: [
                ['x', 0, 1, 2, 3, 4, 5, 6],
                ['data1', 130, 300, 330, 400, 300, 400, 500],
                ['data2', 390, 230, 200, 150, 100, 130, 210],
                ['data3', 290, 430, 300, 160, 210, 170, 190]
    ]
  },
  {
    chartid: 3,
    columns: [
                ['x', 0, 1, 2, 3, 4, 5, 6],
                ['data1', 130, 300, 330, 400, 300, 400, 500],
                ['data2', 390, 230, 200, 150, 100, 130, 210]
    ]
  }
];

var Button = React.createClass({
  handleDelete: function (id) {
    this.props.handleDelete(id);
  },
  render: function() {
    return (
         <button onClick={this.handleDelete.bind(null, 3)}>
            Remove all charts except chart 3
         </button>
    )
  }
});

var Chart = React.createClass({
  componentDidMount() {
    this.chart = c3.generate({
        bindto: '.chart-' + this.props.data.chartid,
        data: {
            columns: this.props.data.columns
        }
    });
  },
  componentWillUnmount() {
    this.chart.destroy();
  },
  render: function() {
    return (
      <div>
        <h4>{"chart-" + this.props.data.chartid}</h4>
        <div className={"chart-" + this.props.data.chartid}>
        </div>
      </div>
      )
  }
});

var Child = React.createClass({
  renderCharts: function(data) {
    return data.map(function(metrics, i) {
      return (
        <Chart key={i} data={metrics} />
      )
    });
  },
  handleDelete: function(id) {
    this.props.handleDelete(id);
  },
  render: function() {
    return (
       <div>
         <Button handleDelete={this.handleDelete} />
         {this.renderCharts(this.props.data)}
       </div>
    ) 
  }
})

var App = React.createClass({
  getInitialState: function() {
    return {
      initialData: this.props.data
    }
  },
  handleDelete: function(id) {
     var _filterFunc = function(data) {
       if (data.chartid == id) return true;
       return false;
     };

     var _filterCharts = Array.prototype.filter.call(this.state.initialData, _filterFunc);

     this.setState({
        initialData: _filterCharts
     })
  },
  render: function() {
    return (
      <div>
        <Child handleDelete={this.handleDelete} data={this.state.initialData} />
      </div>
    );
  }
});

ReactDOM.render(
  <App data={data} />,
  document.getElementById('container')
);

问题在于您在图表上设置关键点的方式。这导致渲染器对您要保留的图表感到困惑。

试试这个: <Chart key={data[i].chartid} data={metrics} /> 而不是 <Chart key={i} data={metrics} />

看看如何React handles keys。请记住,您正在 唯一标识 具有组件生命周期密钥的子组件。因此,由于图表 1 由键“1”唯一标识,您无法使用键“1”呈现图表 3。我上面的解决方案确保图表由其图表 ID 而不是其呈现顺序唯一标识。