【问题标题】:React refs do not update between renderReact refs 不会在渲染之间更新
【发布时间】:2015-06-04 09:11:33
【问题描述】:

所以我有这个组件

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 个 lineitems 的数组

 [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>
    );
  } 
})

【问题讨论】:

  • 如何以及何时更新 lineitem 列表? this.pros.onChange 中传入了什么样的函数?你有更相关的代码吗?
  • 我正在使用通量,因此 lineitem 列表是从 data_store 更新并由父组件传入的。我已经检查过了,这一切正常。传入的 onChange 函数将数据保存到后端,并在 lineitem 更改时更新 store。 onchange 函数调用 getAjaxData()。方法 这是代码中最相关的部分,但我会发布我的其他代码。其他一切都在正常工作。我很确定这是一个反应的事情。因为正在更新的 {lineitems} 组件列表是正确的,甚至具有正确的 refs。
  • 我在 facebooks 文档上阅读了更多关于 refs 的信息。我有点不确定是否可以在初始渲染后动态添加更多引用。我在您的代码中看不到任何错误,所以这是我唯一的理论 atm。继续搜索,也许你能找到一些东西here。 (如果您还没有尝试过)
  • 是的,我也是这么想的。似乎很奇怪,他们不会在每次渲染后更新 refs。我觉得我不能成为唯一一个试图以这种方式弄乱代码的人。也许我在做一些本质上错误的事情,或者反应创造者不赞成?我找到了这个mattzabriskie.com/blog/react-referencing-dynamic-children,但它似乎不是我需要的,因为我没有使用儿童。
  • 从我对文档所说的 refs 的印象来看,应该避免使用它。我看到您正在使用 LineItemRowsWrapper 的参考。我认为您可以将 LineItemsRowsWrapper 中的 ajaxData 传递给从 DocumentContent 发送的 onChange,而无需使用 ref。然后你就可以摆脱那个裁判了。 ref 主要用于在渲染后访问 html 中的数据。您可以使用它来访问孩子,但还有其他可能更多“反应器”的方式来做到这一点。不过(我认为)它并不能解决您的问题。

标签: javascript render reactjs refs


【解决方案1】:

删除所有引用和迭代以读取数据。

应该调用一直向下传递到 LineItem 组件的 onchange 处理程序,并且只传递发生变化的数据。 (单个 LineItem 数据)

然后在组件中使用状态处理 (DocumentContent) 对其进行处理。

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

【讨论】:

  • 我认为包装器实际上在这之后有点多余。
【解决方案2】:

在 React 文档中关于 refs https://facebook.github.io/react/docs/more-about-refs.html 的“警告”部分下

“永远不要在任何组件的 render 方法中访问 refs - 或者 while 任何组件的渲染方法甚至在调用中的任何地方运行 堆栈。”

这正是你正在做的事情。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 2016-05-09
    • 1970-01-01
    • 2020-02-18
    • 2019-08-20
    • 1970-01-01
    • 2018-11-29
    相关资源
    最近更新 更多