React.js处理第三方库安装

React.js handling 3rd party library mounting

本文关键字:安装 第三方 处理 js React      更新时间:2023-09-26

我看到一个使用react组件内部的第三方库的尴尬错误。我能够为这篇文章复制一个人为的演示。

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

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

你可以通过点击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是如何处理密钥的。请记住,您使用组件生命周期的密钥来唯一标识子级。因此,由于图表1是由键"1"唯一标识的,因此无法用键"1)呈现图表3。我上面的解决方案确保了图表是由其图表id而不是其呈现顺序唯一标识的。