[英]Event Handler (prop) passed to child component cannot be called react native
我正在从父组件传递事件处理程序showSpinner()
。 此方法在我的应用程序中显示活动指标,从父类调用时,该方法有效。 但是当我将其传递给子组件然后从子组件中调用它作为this.props.showSpinner()
时,出现了错误
TypeError: undefined is not an object
(evaluating 'Object.keys(this.state.data)')
我也无法在孩子的道具上使用console.log
方法。请注意,我已经在父项上绑定了该功能。
这是我的代码的一部分。 这是父组件。
import React from 'react';
import { View, Button, Alert, Image, ScrollView, BackHandler, TouchableOpacity,Text, ActivityIndicator } from 'react-native';
import ProductListingItem from '../ProductCategories/ProductListingItemCategories.js';
import PusherColumnCategories from '../ProductCategories/PusherColumnCategories.js';
import NavRightButton from '../NavButton/NavRightButton.js';
import ActivitySpinner from '../ActivitySpinner.js';
const TAG = 'PRODUCTCATEGORIESPAGE';
export default class ProductCategoriesPage extends React.Component {
constructor(props) {
super(props);
/*this._getResponseFromApi = this._getResponseFromApi.bind(this);*/
this._onPressGoToCart=this._onPressGoToCart.bind(this);
if(props){
/*console.log(TAG,'constructor()','props available');*/
console.log(TAG,'constructor()','props JSON stringified = '+JSON.stringify(props));
/*this.setState({dataMain : (props.navigation.state.params.categories)});*/
}
this.state = {
dataMain: props.navigation.state.params.categories,
showIndicator: false,
};
console.log(TAG,'constructor','this.state.dataMain = '+this.state.dataMain );
}
static navigationOptions = ({navigation}) => {
return{
title: 'Categories',
headerLeft: null,
headerStyle: {
backgroundColor: '#EE162C',
},
/*headerBackTitleStyle: {
color: 'white',
},*/
headerTintColor: 'white',
headerRight: <NavRightButton navigation= {navigation}/>,
gesturesEnabled:false,
};
};
_onPressGoToCart(){
console.log(TAG,'_onPressGoToCart');
console.log(TAG,'_onPressGoToCart','navigation props ='+JSON.stringify(this.props));
const { navigate } = this.props.navigation;
navigate('CartPage');
}
componentWillReceiveProps(newProps){
console.log(TAG+'componentWillReceiveProps');
if(newProps){
console.log(TAG,'componentWillReceiveProps()','props available');
console.log(TAG,'componentWillReceiveProps()','props = '+newProps.navigation.state.params.categories);
}
}
_OnAlert(title,message){
console.log(TAG,'_onAlert');
Alert.alert(
title,
message,
[
{text:'done',onPress: () => { }}
]
);
}
componentDidMount () {
console.log(TAG,'componentDidMount');
/*this._getResponseFromApi();*/
BackHandler.addEventListener('hardwareBackPress',() => {return true});
}
componentWillMount () {
console.log(TAG,'componentWillMount');
}
_showSpinner(){
console.log(TAG,'_showSpinner');
this.setState({
showIndicator:true,
});
}
_hideSpinner(){
console.log(TAG,'_hideSpinner');
this.setState({
showIndicator:false,
});
}
render(){
console.log(TAG,'render');
console.log(TAG,'render','dataMain = '+this.state.dataMain[0].id);
// console.log(TAG,'render','showSpinner = '+JSON.stringify(this.showSpinner()));
// var tempshowspinner = this.showSpinner.bind(this);
// console.log(TAG,'render','tempshowspinner = '+JSON.stringify(tempshowspinner));
return(
<View
style={{
flex:1,
}}>
<ScrollView style = {{flex:1,
backgroundColor:'#F2F2F2',
}}>
<View style = {{
flex:1,
flexDirection:'column',
}}>
<PusherColumnCategories style = {{
flex:1,
}}
data = {this.state.dataMain}
navigate = {this.props.navigation}
showSpinner = {this._showSpinner}
hideSpinner = {this._hideSpinner}/>
</View>
</ScrollView>
<ActivitySpinner showIndicator={this.state.showIndicator}/>
</View>
);
}
}
这是相应的子组件。
import React from 'react';
import {View, Component, Button} from 'react-native';
import ProductListingItem from './ProductListingItemCategories';
const TAG = "PUSHERCOLUMNCATEGORIES";
export default class PusherColumnCategories extends React.Component {
constructor(props){
super(props);
if(props){
console.log(TAG,'props ='+JSON.stringify(props));
/*console.log(TAG,'props data length = '+Object.keys(props.dataMain).length);*/
console.log(TAG,'Props = '+ JSON.stringify(props.data));
console.log(TAG,'Navigation Props = '+JSON.stringify(props.navigate));
}
this.state = {
data: props.data,
propsAvailable: false,
navigate: props.navigation,
};
};
componentDidMount(){
console.log(TAG,'componentDidMount');
}
componentWillReceiveProps(newProps){
console.log(TAG,'componentWillReceiveProps',newProps.data);
this.setState({
/*data: JSON.parse(JSON.stringify(newProps.data)),*/
data: (newProps.dataMain),
}, function() {
console.log(TAG,'componentWillReceiveProps','this.setState()','data = '+(Object.keys(this.state.data)));
});
}
componentDidUpdate(){
console.log(TAG,'componentDidUpdate');
}
render(){
console.log(TAG,'render()');
if(this.state.data){
console.log(TAG,'render()','state not empty');
console.log(TAG,'render()','data product_code = '+this.state.data[1].product_code);
return(
<View style = {{
flex:1,
flexDirection: 'column',
}}>
<Button
style = {{
flex:1,
}}
title = 'presshere'
onClick = {this.props.showSpinner}
/>
<RenderColumn style = {{
flex:1,
}}
data = {this.state.data}
navigate = {this.props.navigate}
showSpinner = {this.props.showSpinner}
hideSpinner = {this.props.hideSpinner}/>
</View>
);
} else {
console.log(TAG,'render()','state empty');
return(
<View style = {{
flex:1,
flexDirection: 'column',
}}/>
);
}
};
}
编辑 :我实际上发现了真正的问题。 绑定的东西很容易知道,但这不是实际问题的答案。 问题是newProps.dataMain
。 newProps
没有dataMain
键,实际上是data
,如下所示
<PusherColumnCategories style = {{
flex:1,
}}
data = {this.state.dataMain} // the key is `data`, not `dataMain`
navigate = {this.props.navigation}
showSpinner = {this._showSpinner}
hideSpinner = {this._hideSpinner}/>
所以在componentWillReceiveProps
这段代码中
this.setState({
/*data: JSON.parse(JSON.stringify(newProps.data)),*/
data: newProps.data /* not newProps.dataMain */, // newProps.dataMain is not an actual key, so it will set `data` to undefined
}, function() {
console.log(TAG,'componentWillReceiveProps','this.setState()','data = '+(Object.keys(this.state.data))); // if you call `Object.keys` on undefined, you get the error that you posted
});
当执行myFunction.bind(obj)
,您将创建一个新函数,该函数将包装现有函数并记住您传入的对象obj
,并且每当调用该新函数时,它将使用this
obj
设置为obj
来调用原始函数。
在_showSpinner
和_hideSpinner
函数中,您可以使用this.setState
,因此将其设置为父组件很重要, this
您就可以更新父组件的状态,并尝试确保这一点,但是还可以在很多地方不必要地进行绑定,例如在ProductCategoriesPage
的构造函数中,这是不必要的。 而且您还想从下面删除bind(this)
tempshowspinner
的render
功能中的PusherColumnCategories
。 this.props.showSpinner
已经更新了父组件,因为它已绑定到它。 因此,在此处再次进行绑定是多余的,这给人一种错误的印象,即您将其再次绑定到子组件上,而不是这种情况。
下方的Button
组件中的bind(this)
。 您不想出于相同的原因在这里绑定
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.