React.js处理第三方库安装

时间:2016-04-14 13:54:09

标签: javascript reactjs charts c3.js

我看到一个在反应组件中使用第三方库的尴尬错误。我能够为这篇文章重现一个人为的演示。

首先让我解释一下,我正在使用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')
);

1 个答案:

答案 0 :(得分:1)

问题在于您在图表上设置密钥的方式。它导致渲染器对您尝试保留的图表感到困惑。

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

看一下React handles keys的方式。请记住,您唯一地识别具有组件生命周期密钥的子项。因此,由于图表1由键&#34; 1&#34;唯一标识,因此您无法使用键&#34; 1来呈现图表3。&#34;我上面的解决方案确保图表由其图表ID而不是其呈现顺序唯一标识。