无法找到变量道具

时间:2018-04-16 01:44:45

标签: reactjs react-native

我试图在用户点击其中一个列表项时显示详细信息视图。当用户点击listitem时,我收到错误消息,指出Undefined不是对象 评估' this.props.services.ser。以下是错误的屏幕截图:

enter image description here

我的列表项页面代码如下:

    import React, { Component } from 'react';
import { Text, View, StyleSheet, ListView } from 'react-native';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux'
import reducers from '../reducers/ServiceReducer';
import ServiceItem from './ServiceItem';
import Icon from 'react-native-vector-icons/EvilIcons';
import ServiceDetail from './ServiceDetail';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    width: 353,
    flexWrap: 'wrap',
    paddingTop: 20,
    paddingLeft: 20,
  },
});


const store = createStore(reducers);

class AutoCompActivity extends Component {


  renderInitialView() {
    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2,
    });
    this.dataSource = ds.cloneWithRows(this.props.services);

    if (this.props.detailView === true) {
      return (
        <ServiceDetail />
      );
    } else {
      return (
        <ListView 
          enableEmptySections={true}
          dataSource={this.dataSource}
          renderRow={(rowData) => 
            <ServiceItem services={rowData} />
          }
        />
      );
    }
  }

  render() {
    return (
      <View style={styles.container}>
        {this.renderInitialView()}
      </View>
    );
  }
}

const mapStateToProps = state => {
  return { 

    services: state.services,
    detailView: state.detailView,
  };
};
const ConnectedAutoCompActivity = connect(mapStateToProps)(AutoCompActivity);


const app1 = () => (
  <Provider store={store}>
    <ConnectedAutoCompActivity />
  </Provider>
)

export default app1;

我向用户显示的每个项目都在js类serviceItem.js中定义。下面是serviceItem.js的代码。我把整个代码放在TouchableWithoutFeedback中。这是当用户点击其中一个listItem时出现错误的时候。我多次看了这段代码,但无法弄清楚我做错了什么

  import React from 'react';
import { Text, View, StyleSheet, Image,  TouchableWithoutFeedback } from 'react-native';
import { connect } from 'react-redux';
import { getTheme } from 'react-native-material-kit';
import Icon from 'react-native-vector-icons/EvilIcons';
import * as actions from '../actions';

const theme = getTheme();

const styles = StyleSheet.create({
  card: {
    marginTop: 20,
  },
  title: {
      top: 20,
      left: 80,
      fontSize: 24,
  },
  image: {
      height: 100,
  },
  action: {
      backgroundColor: 'black',
      color: 'white',
  },
  icon: {
      position: 'absolute',
      top: 15,
      left: 0,
      color: 'white',
      backgroundColor: 'rgba(255,255,255,0)',
  },
});

const ServiceItem = (props) => {
    return (

        <TouchableWithoutFeedback 
        onPress={() => props.selectServices(props.services)}
    >
        <View style={[theme.cardStyle, styles.card]}>

            <Text >{props.services.ser} </Text>

        </View>
        </TouchableWithoutFeedback>
    );
};


const mapStateToProps = state => {
    return { 
        selectServices: state.selectServices,
        services: state.services
     };
  };



export default connect(mapStateToProps, actions)(ServiceItem);

当用户点击每个列表项时。我正在调用ServiceDetail.js类。下面是serviceDetail.js类的代码:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */
import React, { Component } from 'react';
import { Text, View, StyleSheet, Image, ScrollView, TouchableOpacity, Linking } from 'react-native';
import { connect } from 'react-redux';
import { getTheme } from 'react-native-material-kit';
import EvilIcon from 'react-native-vector-icons/EvilIcons';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import SimpleIcon from 'react-native-vector-icons/SimpleLineIcons';
import * as actions from '../actions';

const theme = getTheme();

const styles = StyleSheet.create({
  card: {
    marginTop: 10,
    paddingBottom: 20,
    marginBottom: 20,
    borderColor: 'lightgrey',
    borderWidth: 0.5,
  },
  title1: {
      top: 10,
      left: 80,
      fontSize: 24,
  },
  title2: {
      top: 35,
      left: 82,
      fontSize: 18,
  },
  image: {
      flex: 0,
      height: 100,
      width: 333,
      backgroundColor: 'transparent',
      justifyContent: 'center',
      alignItems: 'center',
  },
  closeIcon: {
      position: 'absolute',
      top: 5,
      left: 295,
      color: 'rgba(233,166,154,0.8)',
      backgroundColor: 'rgba(255,255,255,0)',
  },  
  icon: {
      position: 'absolute',
      top: 15,
      left: 0,
      color: 'white',
      backgroundColor: 'rgba(255,255,255,0)',
  },
  textArea: {
      flexDirection: 'row',
      paddingLeft: 20,
      paddingTop: 10,
      width: 260,
  },
  textIcons: {
      color: '#26a69a',
  },
  actionArea: {
      paddingTop: 10,
      flexDirection: 'row',
      justifyContent: 'space-around',
      alignItems: 'center',
  },
});
class ServiceDetail extends Component {
    handleClick = (link) => {
        Linking.canOpenURL(link).then(suppported => {
            if (supported) {
                Linking.openURL(link);
            } else {
                console.log('Don\'t know how to open URI: ' + link);
            }
        });
    };
  render() {
    return (
      <ScrollView showsVerticalScrollIndicator={false}>
        <View style={[theme.cardStyle, styles.card]}>
        <Image 
            source={require('../images/background.jpg')}
            style={[theme.cardImageStyle, styles.image]}
        />
        <EvilIcon name={'user'} size={100} style={styles.icon}/>
        <SimpleIcon name={'close'} size={30} style={styles.closeIcon}
            onPress={() => this.props.noneSelected()} />
        <Text style={[theme.cardTitleStyle, styles.title1]}>{this.props.services.ser}</Text>

        <Text style={[theme.cardTitleStyle, styles.title2]}>from {this.props.services.Location}</Text>
        <Text style={[theme.cardTitleStyle, styles.title2]}>from {this.props.services.SecondLoc}</Text>
        <View style={styles.textArea}>
           <MaterialIcon name={'phone'} size={40} style={styles.textIcons}/>
           <Text style={theme.cardContentStyle}>{this.props.services.Phone}</Text>
        </View>
        <View style={styles.textArea}>
           <MaterialIcon name={'email'} size={40} style={styles.textIcons}/>
           <Text style={theme.cardContentStyle}>{this.props.services.email}</Text>
        </View>


        <View style={styles.actionArea}>
            <Text>Call</Text>

            <Text>Email</Text>
        </View>
        </View>
      </ScrollView>
    );
  }
}

const mapStateToProps = state => {
  return { 
      service: state.serviceSelected,
   };
};

export default connect(mapStateToProps, actions)(ServiceDetail);

我的index.js类在actions文件夹下有以下代码:

export const selectServices = (serviceId) => {
    return {
        type: 'SELECTED_SERVICE',
        payload: serviceId,
    };
};

export const noneSelected = () => {
    return {
        type: 'NONE_SELECTED',
    };
};

我的serviceReducer具有以下代码:

   import services from './services.json';

const initialState = {
    services,
    detailView: false,
    serviceSelected: null,
};

export default (state = initialState, action) => {
    switch (action.type) {
        case 'SELECTED_SERVICE':
            return {
                ...state,
                detailView: true,
                serviceSelected: action.payload
            }

        case 'NONE_SELECTED':
            return {
                ...state,
                detailView: false,
                serviceSelected: null,
            }

        default:
            return state;
    }
}

我正在Android模拟器上的Windows机器上开发这个应用程序。我知道我错过了什么。我查看了每一行,但无法弄清楚我做错了什么。我是新来回应原生并试图按照这个例子来制作这个应用程序。我尝试使用chrome调试应用程序,但不断收到无法连接到远程调试的错误。

任何帮助都将受到高度赞赏。

2 个答案:

答案 0 :(得分:0)

我看到你传递道具并将其用于const ServiceItem。您需要使用mapStateToProps,然后转到connect serviceItem.js

const mapStateToProps = state => {
  return { 
      selectServices: state.selectServices,
      services: state.services
   };
};

export default connect(mapStateToProps, actions)(ServiceItem);

您的ServiceDetail.js也应该是:

const mapStateToProps = state => {
  return { 
      services: state.services
   };
};

export default connect(mapStateToProps, actions)(ServiceDetail);

答案 1 :(得分:0)

您的ServiceItem组件只是一个表示组件,在我看来,它不需要连接到redux存储,而是将数据和事件挂钩从父传递到ServiceItem组件,这将工作得很好。这也将解决您的道具问题。

“DennisFrea”提出的观点仍然很好。我只是建议另一个达到同样的目的。