React Native 嵌套渲染函数。关于对象和函数之间的“this”的问题

ReactNative nested render functions. Question regarding `this` between objects and functions

这是我的困惑:

     constructor(props) {
    super(props);
  }

  hookNav(){
    console.log("work");
  }

  renderItem({ item, index }) {
    return (
      <TouchableOpacity style={{ margin: 9 }} onPress={this.hookNav}>
        <View
          style={{
            flex: 1,
            minWidth: 170,
            maxWidth: 223,
            height: 280,
            maxHeight: 280,
            borderRadius: 10,
          }}
        >
          <ImageBackground
            source={{
              uri: "https://picsum.photos/170/223",
            }}
            style={{ flex: 1 }}
            imageStyle={{ borderRadius: 10 }}
          >
            <Text
              style={{
                color: "white",
                position: "absolute",
                bottom: 20,
                right: 10,
                fontWeight: "bold",
                textShadowColor: "black",
                textShadowOffset: { width: -1, height: 1 },
                textShadowRadius: 10,
              }}
            >
              Topic
            </Text>
          </ImageBackground>
        </View>
      </TouchableOpacity>
    );
  }

  render(){
    return (
      <View style={{ marginBottom: 80, backgroundColor: "white" }}>
        <Header
          centerComponent={{ text: "test", style: { color: "orange" } }}
          rightComponent={{ icon: "add", color: "orange" }}
        />
        <FlatList
          numColumns={2}
          onEndReachedThreshold={0}
          onEndReached={({ distanceFromEnd }) => {
            console.debug("on end reached ", distanceFromEnd);
          }}
          contentContainerStyle={styles.list}
          data={[
            { key: "a" },
            { key: "b" },
            { key: "c" },
            { key: "d" },
            { key: "e" },
            { key: "f" },
          ]}
          renderItem={this.renderItem}
          ListHeaderComponent={
            <Text
              style={{ padding: 10, fontWeight: "bold" }}
            >
              Your Topics
            </Text>
          }
        />
      </View>
    );
  }
}

在上面的代码中,当导航到此页面时,会立即抛出一个错误,指出 this.hookNav 未定义。

但是,当我将 hookNav 函数放在状态对象中时,就像这样

constructor(props) {
    super(props);
    state = {
      hookNav : function() {
       console.log("work please");
      }
    }
  }

并且在 onPress 里面 renderItem

const { hookNav} = this.state;
    return (
      <TouchableOpacity style={{ margin: 9 }} onPress={hookNav}>

这按预期工作。

据我了解,render 已经可以通过 this 访问组件的 state。如果renderItem可以通过this访问state对象,为什么不能直接访问this.hookNav()呢?为什么函数需要封装在一个对象中才能运行?

谢谢。

这是因为任何 Javascript 函数中 this 的值取决于该函数的调用方式。

在您的非工作示例中,this.hookNavrenderItem 方法内部。因此它将采用该方法的 this - 正如我刚才所说,这取决于它的调用方式。进一步检查您的代码表明 renderItem 方法不是由您的组件直接调用的,而是作为 FlatList 组件的道具(称为 renderItem)传递的。现在我不知道该组件是如何实现的(我从未使用过 React Native),但几乎可以肯定它会在某个时候调用该函数——当它调用时,它不可能在您的组件的上下文中。这是因为 FlatList 不可能知道那个函数 prop 来自哪里,当它调用它时,它将被视为一个“普通”函数,而不是在任何特定对象的上下文中。所以它的 this 上下文不会像预期的那样是您的组件实例,而只是全局对象——它没有任何 hookNav 方法。

这个问题在你的第二个例子中没有发生,因为你只是访问函数作为 this.state 的一部分 - 没有传递方法,就像前面例子中的 renderItem 一样,这取决于内部 this 参考。请注意,如果您的 hookNav 指的是其中的 this,则情况并非如此。

这种 this 上下文的问题在 React 中很常见,但幸运的是有两个通用的解决方案可以解决这个问题:

  1. 在组件的构造函数中绑定方法。如果在第一个示例中,构造函数包含语句 this.renderItem = this.renderItem.bind(this);,那么它将正常工作。 (请注意,这是官方 React docs 推荐的。)从技术上讲,这是“最佳”解决方案(性能略好于其他选项)——但如果你有很多方法,它确实涉及相当多的样板文件需要这样的绑定。

  2. 改用箭头函数来定义方法。而不是renderItem({ item, index }) {...},写成renderItem = ({ item, index }) => {...}。这是可行的,因为箭头函数采用了它们词法范围的 this,这将是 class 本身——所以换句话说,this 将始终引用组件实例,正如您几乎总是希望的那样.

如果这令人困惑,请不要担心 - JS 中 this 关键字的行为是 JS 初学者的常见绊脚石,对于那些更有经验的人来说也经常如此。网上有很多很好的解释可以揭开它的神秘面纱,我特别推荐this one.

您必须将方法绑定到 class 的 this。一种方法如下所示。

constructor(props){
  super(props);
  this.renderItem = this.renderItem.bind(this);
}