“这个"之谜在 ReactJS 中 [英] Mystery of "this" in ReactJS

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

问题描述

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

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

 var CompanyApp = React.createClass({getInitialState:函数(){返回 {companylist:this.props.companies};},handleNewRowSubmit:函数(新公司){this.setState( {companylist: this.state.companylist.concat([newcompany])} );},handleCompanyRemove:函数(公司){无功指数 = -1;var clength = this.state.companylist.length;for( var i = 0; i < clength; i++ ) {if( this.state.companylist[i].cname === company.cname ) {指数 = i;休息;}}this.state.companylist.splice( index, 1 );this.setState( {companylist: this.state.companylist} );},渲染:函数(){var tableStyle = {width: '100%'};var leftTdStyle = {width: '50%',padding:'20px',verticalAlign: 'top'};var rightTdStyle = {width: '50%',padding:'20px',verticalAlign: 'top'};返回 (<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>);}});var CompanyList = React.createClass({handleCompanyRemove:函数(公司){this.props.onCompanyRemove(公司);},渲染:函数(){var 公司 = [];var that = this;//TODO:需要找出原因 = 这使它起作用;收到 onCompanyDelete 不是未定义的错误this.props.clist.forEach(function(company) {company.push(<Company company={company} onCompanyDelete={that.handleCompanyRemove}/>);});返回 (<div><h3>公司名单</h3><table className="table table-striped"><thead><tr><th>公司名称</th><th>员工</th><th>总公司</th><th>行动</th></tr>;</thead><tbody>{公司}</tbody>

);}});var 公司 = React.createClass({handleRemoveCompany:函数(){this.props.onCompanyDelete( this.props.company );返回假;},渲染:函数(){返回 (<tr><td>{this.props.company.cname}</td><td>{this.props.company.ecount}</td><td>{this.props.company.hoffice}</td><td><输入类型=按钮"className =btn btn-primary";值=删除"onClick={this.handleRemoveCompany}/></td></tr>);}});var NewRow = React.createClass({句柄提交:函数(){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 = '';返回假;},渲染:函数(){var inputStyle = {padding:'12px'}返回 (<div className=好"><h3>添加一个公司</h3><form onSubmit={this.handleSubmit}><div className="input-group input-group-lg";样式={输入样式}><输入类型=文本"className="form-control col-md-8";占位符=公司名称"ref=cname"/>

<div className="input-group input-group-lg";样式={输入样式}><输入类型=文本"className="form-control col-md-8";占位符=员工人数"ref=ecount"/>

<div className="input-group input-group-lg";样式={输入样式}><输入类型=文本"className="form-control col-md-8";占位符=总部"ref=hoffice"/>

<div className="input-group input-group-lg";样式={输入样式}><输入类型=提交"className =btn btn-primary";value=添加公司"/>

</表单>

);}});var defCompanies = [{cname:"Infosys Technologies",ecount:150000,hoffice:"Bangalore"},{cname:"TCS",ecount:140000,hoffice:"Mumbai"}];React.renderComponent( <CompanyApp Companies={defCompanys}/>, document.getElementById( "companyApp" ) );

这是对 ReactJS 工作原理的非常好的基本解释.感谢作者.

但是这个评论,

<块引用>

var that = this;//TODO:需要找出原因 = 这使它起作用;收到 onCompanyDelete 不是未定义的错误

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

提前致谢.

解决方案

ReactJS 特有的这个"并不神秘.

这只是 JavaScript 回调中出现的标准范围问题的一个例子.

当您在 React 组件中时,基础组件上的所有方法都将被限定为 this 作为当前组件,就像任何其他 JavaScript类"一样.

在您的代码片段中,您有一个 render 方法,它是基础组件上的一个函数,因此 this 等于组件本身.但是,在该渲染方法中,您使用 this.props.clist.forEach 调用回调,render 方法内的任何函数回调都需要绑定到正确的this 作用域,或者你可以做 var that = this(虽然这是一种反模式,应该被阻止)`.

示例,代码段的略微简化版本:

var MyComponent = React.createClass({handleCompanyRemove:函数(e){//...},渲染:函数(){//this === MyComponent 在这个范围内this.props.someArray.forEach(function(item) {//this !== MyComponent,因此 this.handleCompanyRemove 不能//叫做!})}})

正如您从上面的评论中看到的,在 .forEach 的回调中,您不能直接使用 this 而不在外部定义变量或正确绑定函数.

解决此问题的其他选项是:

绑定回调函数到正确的这个范围.示例:

this.props.someArray.forEach(function(item) {//this === MyComponent 现在也在这个范围内!//所以你可以毫无问题地调用 this.handleCompanyRemove}.bind(this))

如果您使用 Babel/ES6,您可以使用 Fat Arrow 函数语法,以保证 this 作用域继续从父作用域进行回调.示例:

this.props.someArray.forEach((item) => {//this === MyComponent 现在也在这个范围内!//所以你可以毫无问题地调用 this.handleCompanyRemove})

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

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

But this comment,

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?

Thanks in advance.

解决方案

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

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

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".

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

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

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天全站免登陆