簡體   English   中英

傳遞給子組件的事件處理程序(prop)不能稱為react native

[英]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)

  • tempshowspinnerrender功能中的PusherColumnCategories this.props.showSpinner已經更新了父組件,因為它已綁定到它。 因此,在此處再次進行綁定是多余的,這給人一種錯誤的印象,即您將其再次綁定到子組件上,而不是這種情況。

  • 下方的Button組件中的bind(this) 您不想出於相同的原因在這里綁定

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM