在涉及参数时,避免在render()方法中创建函数的最佳技术

时间:2016-05-31 09:11:56

标签: javascript reactjs

我将举例说明我的问题......

说我有以下数据:

const widgets = [
  { id: 1, name: 'Foo' },
  { id: 2, name: 'Bob' }
];

它作为prop传递给组件,然后映射到元素中,如下所示:

class WidgetSelector extends Component {
  onSelected = (widget) => {
    console.log('Selected widget: ', widget);
  }

  render() {
    return (
      <div>
         {
           this.props.widgets.map((widget, i) => 
            <button key={i} onClick={() => this.onSelected(widget)}>
              {widget.name}
            </button>
           )
         }
      </div>
    );
  }
}

它在表面区域似乎没问题,但它正在打破performance optimisation guidelines,因为每个render()都会创建一个新的函数实例(参见onClick={() => onSelected(widget)})。因此,这会破坏子组件的“纯粹”更新特性,并且每次父渲染调用都会强制进行子渲染,即使可能没有对子组件进行任何实际更改。

我链接的文章引用了构造函数中的早期绑定机制,但我的情况不同,我需要根据props传递参数。

避免此类情况的推荐模式是什么?

我应该在组件的构造函数中创建一个函数数组,然后通过索引引用函数吗?像这样:

class WidgetSelector extends Component {
  constructor(props) {
    super(props);
    this.widgetSelectors = props.widgets.map(
      widget => () => this.onSelected(widget)
    );
  }

  ...

  render() {
    return (
      <div>
         {
           this.props.widgets.map((widget, i) => 
            <button key={i} onClick={this.widgetSelectors[i]}>
              {widget.name}
            </button>
           )
         }
      </div>
    );
  }
}

这有效,但这是解决这个问题最优雅的方法吗?

如果你想玩,我已经创建了这个解决方案的webpackbin实现:http://www.webpackbin.com/4ybibSU7b

3 个答案:

答案 0 :(得分:1)

您引用的文章通过早期绑定指出了解决方法

class WidgetSelector extends Component {
  constructor(props) {
    super(props);
    this.onSelected = this.onSelected.bind(this);
  }
  onSelected(e) {
    console.log(e.target.innerHTML);
  }
  render() {
    return (
      <div>
      {
        this.props.widgets.map((widget, i) => 
          <button key={i} onClick={this.onSelected}>
          {widget.name}
          </button>
         )
      }
      </div>
    );
  }
}

但是这样你就无法直接将参数传递给函数。

答案 1 :(得分:1)

您可以将数据作为属性添加到元素上,并以这种方式引用它:

var Container = React.createClass({
  data: ['foo', 'bar'],
  handleClick: function(e) {
    console.log(e.target.getAttribute('data-item'))
  },
  render: function() {
    return <div>
        {this.data.map(d =>
            <button key={d} data-item={d} onClick={this.handleClick}>{d}</button>)}
    </div>;
  }
});

JSFiddle

答案 2 :(得分:0)

尝试;

<button key={i} onClick={onSelected.bind(this, widget)}>