简体   繁体   English

如何在ListView的renderRow中访问`this`?

[英]How to access `this` inside a renderRow of a ListView?

I'm having trouble to run a function for the onPress event inside a row of a ListView . 我在ListView的一行内为onPress事件运行函数时遇到麻烦。 I'm following the React Native tutorial trying to continue from there. 我正在关注React Native教程,试图从那里继续。 It seems it's using ES6 syntax style. 似乎它使用的是ES6语法样式。

This is the relevant part of the code. 这是代码的相关部分。

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */

import React, {  
  TouchableHighlight,
  AppRegistry,
  Component,
  Image,
  ListView,
  StyleSheet,
  Text,
  View,
  Alert,
} from 'react-native';

class AwesomeProject extends Component {
  constructor(props) {
    super(props);
    this.something = this.something.bind(this); // <-- Trying this, not even sure why
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  }

//
//Irrelevant code here. Fetching stuff and renderLoadingView
//

  something = function(){
    console.log('something');
    Alert.alert(
      'Alert Title',
      'alertMessage',
    );
  }


  render() {
    console.log('this', this); //this is an instance of AwesomeProject
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderMovie}
        style={styles.listView}
        />
    );
  }

  renderMovie(movie) {
    console.log('Not this', this); //this is not an instance of AwesomeProject
    return (
      <TouchableHighlight onPress={() => {console.log(this); this.something()}}>
     <View style={styles.container}>
        <Image
          source={{uri: movie.posters.thumbnail}}
          style={styles.thumbnail}                    
        />
        <View style={styles.rightContainer}>
          <Text style={styles.title}

          >{movie.title}</Text>
          <Text style={styles.year}>{movie.year}</Text>
        </View>
      </View>
       </TouchableHighlight>
    );
  }
}

//
//More irrelevant code here. Styles and the 
//

AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);

I'm unable to run the something function. 我无法运行something函数。 I've tried various syntax without success. 我尝试了各种语法,但没有成功。 The problem seems to be that this is not what I expect it to be, and it doesn't have the variable something defined. 这个问题似乎是, this不是我希望它是,并且它不具有可变something定义。

The only way I had to make it work was to declare an external variable with var something = function(){...} outside the AwesomeProject class. 我必须使其起作用的唯一方法是在AwesomeProject类外部使用var something = function(){...}声明一个外部变量。

Is there a way to access something while being declared inside AwesomeProject ? AwesomeProject中声明时,是否可以访问something AwesomeProject Is this maybe a bad practice according to flux architecture or something? 根据磁通架构,这可能是不好的做法吗?

Turns out I found the solution myself, here: https://github.com/goatslacker/alt/issues/283#issuecomment-115391700 原来我自己在这里找到了解决方案: https : //github.com/goatslacker/alt/issues/283#issuecomment-115391700

The problem is that with ES6 syntax you have no autobinding of this , so you need to do it yourself. 问题是,与ES6语法,你有没有自动绑定 this ,所以你需要自己做。

I've learned a bit more since I posted this answer. 自发布此答案以来,我学到了更多。 The real problem is that this is "bound" when the function is executed, not when it's declared. 真正的问题是在执行函数时(而不是在声明时) this是“绑定”的。 It points to the object the function is attached to when called . 它指向函数在调用时附加的对象。 For example: 例如:

 obj.foo(); //inside foo, this points to obj bar(); //inside bar, this points to the global object (or undefined in strict mode) 

In my example the function this.renderMovie() is passed as a parameter. 在我的示例中,函数this.renderMovie()作为参数传递。 So inside ListView it will be a "local variable". 因此,在ListView中它将是一个“局部变量”。 It will be called "detached" from any object, like the bar() example before, so this will not be what I expect. 它将被称为与任何对象“分离”,例如之前的bar()示例,因此this不是我期望的。

It's possible to force the binding of this . 可以强制this绑定。

There are 3 possible solutions to my problem, and I like the 3rd one the best: 有3种可能的解决方案,我最喜欢第3种:

Option 1: Manually bind this on call 选项1:在通话时手动绑定

On the code, replace the referece to {this.renderMovie} whith {this.renderMovie.bind(this)} 在代码上,将{this.renderMovie}替换为{this.renderMovie.bind(this)}

  render() {
    console.log('this', this); //this is an instance of AwesomeProject
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderMovie.bind(this)} //<-- change here
        style={styles.listView}
        />
    );
  }

Option 2: Do the binding on the constructor 选项2:对构造函数进行绑定

And of course, bind the right function: 当然,绑定正确的函数:

  constructor(props) {
    super(props);
    this.something = this.something.bind(this); // <-- Not this function
    this.renderMovie = this.renderMovie.bind(this); // <-- This function!!
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  }

Option 3: use the arrow syntax and let them do the job 选项3:使用箭头语法,让他们完成工作

I like this one the best. 我最喜欢这个。 You just need to declare the involved function using the arrow syntax so this: 您只需要使用箭头语法声明所涉及的函数,因此:

  renderMovie(movie) {
    //code here
  }

becomes this: 变成这个:

  renderMovie = (movie) => {
    //code here
  }

In addition to https://stackoverflow.com/a/36779517/6100821 除了https://stackoverflow.com/a/36779517/6100821

Option 4: use bind operator 选项4:使用绑定运算符

<ListView
    dataSource={this.state.dataSource}
    renderRow={::this.renderMovie} //<-- cleaner, than bind
    style={styles.listView}
    />

Be careful, it's just a proposal , not a standard! 注意,这只是一个建议 ,而不是标准!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM