【问题标题】:React.js handling 3rd party library mountingReact.js 处理第三方库安装
【发布时间】:2016-04-14 22:11:57
【问题描述】:

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

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

【问题讨论】:

    标签: javascript reactjs charts c3.js


    【解决方案1】:

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

    试试这个: &lt;Chart key={data[i].chartid} data={metrics} /&gt; 而不是&lt;Chart key={i} data={metrics} /&gt;

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

    【讨论】:

    • 是的,你是对的!这是有道理的,因为我分配的键实际上只是基于map 循环并且实际上与图表无关,所以我假设 - 图表 3 在被过滤时收到key={1}。我这样说对吗?
    • 完全正确。这种行为有点违反直觉,但请记住,正是这些优化让 React 拥有它所拥有的高性能。
    猜你喜欢
    • 2014-03-23
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多