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.hookNav
在 renderItem
方法内部。因此它将采用该方法的 this
- 正如我刚才所说,这取决于它的调用方式。进一步检查您的代码表明 renderItem
方法不是由您的组件直接调用的,而是作为 FlatList
组件的道具(称为 renderItem
)传递的。现在我不知道该组件是如何实现的(我从未使用过 React Native),但几乎可以肯定它会在某个时候调用该函数——当它调用时,它不可能在您的组件的上下文中。这是因为 FlatList
不可能知道那个函数 prop 来自哪里,当它调用它时,它将被视为一个“普通”函数,而不是在任何特定对象的上下文中。所以它的 this
上下文不会像预期的那样是您的组件实例,而只是全局对象——它没有任何 hookNav
方法。
这个问题在你的第二个例子中没有发生,因为你只是访问函数作为 this.state
的一部分 - 没有传递方法,就像前面例子中的 renderItem
一样,这取决于内部 this
参考。请注意,如果您的 hookNav
指的是其中的 this
,则情况并非如此。
这种 this
上下文的问题在 React 中很常见,但幸运的是有两个通用的解决方案可以解决这个问题:
在组件的构造函数中绑定方法。如果在第一个示例中,构造函数包含语句 this.renderItem = this.renderItem.bind(this);
,那么它将正常工作。 (请注意,这是官方 React docs 推荐的。)从技术上讲,这是“最佳”解决方案(性能略好于其他选项)——但如果你有很多方法,它确实涉及相当多的样板文件需要这样的绑定。
改用箭头函数来定义方法。而不是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);
}
这是我的困惑:
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.hookNav
在 renderItem
方法内部。因此它将采用该方法的 this
- 正如我刚才所说,这取决于它的调用方式。进一步检查您的代码表明 renderItem
方法不是由您的组件直接调用的,而是作为 FlatList
组件的道具(称为 renderItem
)传递的。现在我不知道该组件是如何实现的(我从未使用过 React Native),但几乎可以肯定它会在某个时候调用该函数——当它调用时,它不可能在您的组件的上下文中。这是因为 FlatList
不可能知道那个函数 prop 来自哪里,当它调用它时,它将被视为一个“普通”函数,而不是在任何特定对象的上下文中。所以它的 this
上下文不会像预期的那样是您的组件实例,而只是全局对象——它没有任何 hookNav
方法。
这个问题在你的第二个例子中没有发生,因为你只是访问函数作为 this.state
的一部分 - 没有传递方法,就像前面例子中的 renderItem
一样,这取决于内部 this
参考。请注意,如果您的 hookNav
指的是其中的 this
,则情况并非如此。
这种 this
上下文的问题在 React 中很常见,但幸运的是有两个通用的解决方案可以解决这个问题:
在组件的构造函数中绑定方法。如果在第一个示例中,构造函数包含语句
this.renderItem = this.renderItem.bind(this);
,那么它将正常工作。 (请注意,这是官方 React docs 推荐的。)从技术上讲,这是“最佳”解决方案(性能略好于其他选项)——但如果你有很多方法,它确实涉及相当多的样板文件需要这样的绑定。改用箭头函数来定义方法。而不是
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);
}