13

所以我有这个组件

var LineItemRowsWrapper = React.createClass({
  current_lineitem_count: 0,

  getAjaxData: function(){
    var lineitem_data  = [];
    for(var i = 0; i < this.current_lineitem_count; i++){
        var data = this.refs['lineitem_'+i].getAjaxData();

        lineitem_data.push(data)
    }
    return lineitem_data;
  },

  getLineitems: function(){
    var self = this;

    var lineitem_components = [];
    this.current_lineitem_count = 0;
    if(this.props.shoot){
      var preview = this.props.preview;

      var lineitems = this.props.shoot.get_lineitems();


      lineitem_components = lineitems.map(function (item, index) {
          var ref_str = 'lineitem_'+self.current_lineitem_count;
          self.current_lineitem_count++;

          return (
            <LineItemRow item={item} key={index} ref={ref_str} preview={preview} onChange={self.props.onChange} />
          )
        });
      }

    return lineitem_components;
  },

  render: function() {
    var lineitems = this.getLineitems();
    return (
      <div>
        {lineitems}
      </div>
    )
  }
})

第一次渲染 lineitems 时,refs 会像预期的那样工作。但是,如果我向 this.props.shoot 添加一个 lineitem,则该组件的 refs 对象不会改变。

因此,例如说我有一个包含 3 个 lineitem 的数组

 [i1,i2,i3]

this.refs 将是

 {lineitem_0:{}, lineitem_1:{}, lineitem_2:{}}

当我将我的 lineitem 数组更新为

 [i1,i2,i3,i4]

this.refs 没有改变,它仍然是

 {lineitem_0:{}, lineitem_1:{}, lineitem_2:{}}

为什么 refs 对象在渲染之间不更新?LineItemRow 组件会正确更新,所以我知道这方面没有问题。任何见解将不胜感激!

____Edit____(要求为上下文添加更多代码)

var DocumentContent = React.createClass({
  contextTypes: {
    router: React.PropTypes.func.isRequired
  },

  getParams: function(){
    return this.context.router.getCurrentParams()
  },

  getInitialState: function() {
    return {
      shoot: ShootStore.get_shoot(this.getParams().shoot_id),
    }
  },

  componentWillMount: function() {  
    ShootStore.bind( 'change', this.onStoreUpdate );
  },

  componentWillUnmount: function() {  
    ShootStore.unbind( 'change', this.onStoreUpdate );
  },

  onStoreUpdate: function(){
    this.setState(this.getInitialState());
  },



  addLineItem: function() {
      ShootActions.create_lineitem(this.state.shoot.id);
  },


  update_shoot_timeout: null,

  update_shoot:function(){
    var self = this;
    window.clearTimeout(this.update_shoot_timeout)
    this.update_shoot_timeout = window.setTimeout(function(){

        var lineitem_data = self.refs.lineitems.getAjaxData()

        if(self.props.shoot){
            ShootActions.update_shoot(self.state.shoot.id, lineitem_data )
        }
    }, 500)
  },


  render: function() {

    var shoot = this.state.shoot;
    return (
        <div className='document__content'>
            <div className='row'>


            <div className='document__expenses'>
                <h3 className='lineitem__title'> Expenses </h3>
                <LineItemRowsWrapper shoot={shoot} onChange={this.update_shoot} ref='lineitems'/>

            </div>
            <button onClick={this.addLineItem} className="btn-small btn-positive">   
                       + Add Expense
                    </button>  




        </div>
    );
  } 
})
4

2 回答 2

11

在有关参考的反应文档中的“警告”部分下https://facebook.github.io/react/docs/more-about-refs.html

“永远不要访问任何组件的渲染方法内部的引用 - 或者当任何组件的渲染方法甚至在调用堆栈中的任何位置运行时。”

这正是您正在做的事情。

相反,您应该将有关组件的状态this.state或组件的属性存储在this.props

于 2015-10-12T20:47:46.063 回答
0

删除所有参考和迭代以读取数据。

应该调用您一直向下传递到 LineItem 组件的 onchange 处理程序并仅传递更改的数据。(单个 LineItem 数据)

然后使用状态处理 (DocumentContent) 在组件处处理它。

创建一个动作 ShootActions.updateLineItem() 来更新商店中的相关订单项,然后发出更改并再次呈现所有内容。

于 2015-04-15T05:49:27.593 回答