“这个"的奥秘在ReactJS中 [英] Mystery of "this" in ReactJS

查看:60
本文介绍了“这个"的奥秘在ReactJS中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Facebook的React世界还很陌生.他们的文档似乎非常好,但是在某些方面我需要稍微澄清一下.这就是其中之一.

I am fairly new to the Facebook's React world. Their documentation seems to be very good but there are a few areas where I need a little bit of clarity. This is one of them.

Src: http://tuts-javascript.appspot.com/reactjs-add-remove-table-row

    var CompanyApp = React.createClass({
    getInitialState: function() {
      return {companylist:this.props.companies};
    },
    handleNewRowSubmit: function( newcompany ) {
      this.setState( {companylist: this.state.companylist.concat([newcompany])} );
    },
    handleCompanyRemove: function( company ) {
      
      var index = -1;   
      var clength = this.state.companylist.length;
        for( var i = 0; i < clength; i++ ) {
            if( this.state.companylist[i].cname === company.cname ) {
                index = i;
                break;
            }
        }
        this.state.companylist.splice( index, 1 );  
        this.setState( {companylist: this.state.companylist} );
    },
    render: function() {
      var tableStyle = {width: '100%'};
      var leftTdStyle = {width: '50%',padding:'20px',verticalAlign: 'top'};
      var rightTdStyle = {width: '50%',padding:'20px',verticalAlign: 'top'};
      return ( 
        <table style={tableStyle}>
          <tr>
            <td style={leftTdStyle}>
              <CompanyList clist={this.state.companylist}  onCompanyRemove={this.handleCompanyRemove}/>
            </td>
            <td style={rightTdStyle}>
              <NewRow onRowSubmit={this.handleNewRowSubmit}/>
            </td>
          </tr>
      </table>
      );
    }
  });
  
  var CompanyList = React.createClass({
    handleCompanyRemove: function(company){
      this.props.onCompanyRemove( company );
    },
    render: function() {
      var companies = [];
      var that = this; // TODO: Needs to find out why that = this made it work; Was getting error that onCompanyDelete is not undefined
      this.props.clist.forEach(function(company) {
        companies.push(<Company company={company} onCompanyDelete={that.handleCompanyRemove} /> );
      });
      return ( 
        <div>
          <h3>List of Companies</h3>
          <table className="table table-striped">
            <thead><tr><th>Company Name</th><th>Employees</th><th>Head Office</th><th>Action</th></tr></thead>
            <tbody>{companies}</tbody>
          </table>
        </div>
        );
    }
  });
  
  var Company = React.createClass({
    handleRemoveCompany: function() {
      this.props.onCompanyDelete( this.props.company );
      return false;
    },
    render: function() {
      return (
        <tr>
          <td>{this.props.company.cname}</td>
          <td>{this.props.company.ecount}</td>
          <td>{this.props.company.hoffice}</td>
          <td><input type="button"  className="btn btn-primary" value="Remove" onClick={this.handleRemoveCompany}/></td>
        </tr>
        );
    }
  });
  
  var NewRow = React.createClass({
    handleSubmit: function() {
      var cname = this.refs.cname.getDOMNode().value;
      var ecount = this.refs.ecount.getDOMNode().value;
      var hoffice = this.refs.hoffice.getDOMNode().value;
      var newrow = {cname: cname, ecount: ecount, hoffice: hoffice };
      this.props.onRowSubmit( newrow );
      
      this.refs.cname.getDOMNode().value = '';
      this.refs.ecount.getDOMNode().value = '';
      this.refs.hoffice.getDOMNode().value = '';
      return false;
    },
    render: function() {
      var inputStyle = {padding:'12px'}
      return ( 
        <div className="well">
          <h3>Add A Company</h3>
        <form onSubmit={this.handleSubmit}>
          <div className="input-group input-group-lg" style={inputStyle}>
            <input type="text"  className="form-control col-md-8"  placeholder="Company Name" ref="cname"/>
          </div>
          <div className="input-group input-group-lg" style={inputStyle}>
            <input type="text"  className="form-control col-md-8" placeholder="Employee Count" ref="ecount"/>
          </div>
          <div className="input-group input-group-lg" style={inputStyle}>
            <input type="text"  className="form-control col-md-8" placeholder="Headoffice" ref="hoffice"/>
          </div>
          <div className="input-group input-group-lg" style={inputStyle}>
            <input type="submit"  className="btn btn-primary" value="Add Company"/>
          </div>
        </form>
        </div>
        );
    }
  });
  var defCompanies = [{cname:"Infosys Technologies",ecount:150000,hoffice:"Bangalore"},{cname:"TCS",ecount:140000,hoffice:"Mumbai"}];
  React.renderComponent( <CompanyApp companies={defCompanies}/>, document.getElementById( "companyApp" ) );

这是一个关于ReactJS工作原理的很好的基本解释.感谢作者.

This is a very good basic explanation of how ReactJS works. Thanks to the author.

但是这个评论,

var that = this;//TODO:需要找出原因,这使它起作用了;出现错误,提示onCompanyDelete尚未定义

var that = this; // TODO: Needs to find out why that = this made it work; Was getting error that onCompanyDelete is not undefined

那为什么有必要?这是正确的方法吗?如果没有,那是什么?

Why is that necessary? Is this the right way to do it? If not, what is?

谢谢.

推荐答案

ReactJS没有"this"的神秘之处.

There's no mystery of "this" that is specific to ReactJS.

这只是标准范围界定问题的一种情况,这些问题随着JavaScript中的回调而出现.

This is just a case of standard scoping issues that crop up with callbacks in JavaScript.

当您处于react组件中时,就像其他任何JavaScript类"一样,基本组件上的所有方法都将以 this 作为当前组件来确定范围.

When you're in a react component, all methods on the base component will be scoped with the this being the current component, just like any other JavaScript "class".

您的代码段中有一个 render 方法,该方法是基础组件上的函数,因此 this 等于组件本身.但是,在该render方法中,您要使用 this.props.clist.forEach 调用回调,因此 render 方法内部的任何函数回调都必须绑定到正确的 this 作用域,或者您也可以执行 var that = this (尽管这是反模式,应避免使用).

In your snippet you have a render method which is a function on the base component and therefore this is equal to the component itself. However within that render method you're calling a callback with this.props.clist.forEach, any function callbacks inside the render method will need to be either bound to the correct this scope, or you can do var that = this (although this is an anti-pattern and should be discouraged)`.

例如,您的代码段的简化版本:

Example, slightly simplified version of your snippet:

var MyComponent = React.createClass({
    handleCompanyRemove: function(e) {
        // ...
    },
    render: function() {
        // this === MyComponent within this scope

        this.props.someArray.forEach(function(item) {
            // this !== MyComponent, therefore this.handleCompanyRemove cannot
            // be called!
        })
    }
})

从上面的注释中可以看到,在 .forEach 的回调内部,如果没有在外部定义变量或正确绑定该函数,则无法直接使用 this

As you can see from the comments above, inside your callback for the .forEach you cannot use this directly without either defining a variable outside, or properly binding the function.

其他解决此问题的方法是:

Other options to solve this are:

绑定回调函数以更正此作用域.示例:

Binding the callback function to the correct this scope. Example:

this.props.someArray.forEach(function(item) {
    // this === MyComponent within this scope too now!
    // so you can call this.handleCompanyRemove with no problem
 }.bind(this))

如果您使用的是Babel/ES6,则可以使用 Fat Arrow (函数箭头)功能语法,该语法可确保 this 范围继续从父范围进行回调.示例:

If you're using Babel/ES6 you can use the Fat Arrow function syntax which guarantees that this scope continues to the callback from the parent scope. Example:

this.props.someArray.forEach((item) => {
    // this === MyComponent within this scope too now!
    // so you can call this.handleCompanyRemove with no problem
})

这篇关于“这个"的奥秘在ReactJS中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆