javascript React refs 不会在渲染之间更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29361703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 10:25:00  来源:igfitidea点击:

React refs do not update between render

javascriptrenderreactjsrefs

提问by Charles Haro

So I have this component

所以我有这个组件

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

the first time lineitems are rendered the refs work like expected. But if I add a lineitem to this.props.shoot the refs object of this component does not change.

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

So for example say I had an array of 3 lineitems

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

 [i1,i2,i3]

this.refs would be

this.refs 将是

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

and when I update my lineitem array to be

当我将 lineitem 数组更新为

 [i1,i2,i3,i4]

this.refs does not change, it will still be

this.refs 不会改变,它仍然会

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

why doesn't the refs object update between renders? The LineItemRow components update properly so I know its not something wrong on that front. Any insights would be much appreciated!

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

____Edit____ (requested to add more code for context)

____编辑____(要求为上下文添加更多代码)

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

回答by jeff_kile

Under the section "Caution" in the react documentation about refs https://facebook.github.io/react/docs/more-about-refs.html

在关于 refs https://facebook.github.io/react/docs/more-about-refs.html的反应文档中的“注意”部分下

"Never access refs inside of any component's render method - or while any component's render method is even running anywhere in the call stack."

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

Which is exactly what you're doing.

这正是你在做什么。

Instead you should store state about the component in this.stateor properties of the component in this.props

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

回答by dannyshaw

Remove all your refs and iteration to read the data.

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

The onchange handler you pass all the way down to the LineItem component should be called and passed only the data that changes. (The single LineItem data)

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

This is then handled back at the component with the state handling (DocumentContent).

然后通过状态处理 (DocumentContent) 在组件处处理回。

Create an action ShootActions.updateLineItem() that updates the relevant line item in the store, which then emits the change and everything renders again.

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