hengjuice
hengjuice

Reputation: 1

I have this issue undefined is not an object (evaluating 'this.state.dataSource.map')

I want to display a list of places from a online json url.

import React, { Component } from "react";
import {
  View,
  StyleSheet,
  Dimensions,
  Image,
  StatusBar,
  TextInput,
  TouchableOpacity,
  Text,
  Button,
  Platform,
  Alert,
  FlatList,
  ActivityIndicator,
} from "react-native";

let url = "https://cz2006api.herokuapp.com/api/getAll";
let url2 = "";

export default class ClinicComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      dataSource: null,
    };
  }

  componentDidMount() {
    return fetch("https://cz2006api.herokuapp.com/api/getAll")
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({
          isLoading: false,
          dataSource: responseJson.data.data,
        });
      })
      .catch((error) => {
        console.log(error);
      });
  }
  render() {
    if (this.state.isLoading) {
      return (
        <View style={styles.container}>
          <ActivityIndicator />
        </View>
      );
    } else {
      let hospitals = this.state.dataSource.map((val, key) => {
        return (
          <View key={key} style={styles.item}>
            <Text>{val.name}</Text>
          </View>
        );
      });
      return (
        <View style={styles.item}>
          {/* <Text>Content Loaded</Text> */}
          {hospitals}
        </View>
      );
    }
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  item: {
    flex: 1,
    alignSelf: "stretch",
    margin: 10,
    alignItems: "center",
    justifyContent: "center",
    borderBottomWidth: 1,
    borderBottomColor: "#eee",
  },
});

Unfortunately when i tried to run this via expo cli I got an error, saying undefined is not an object enter image description here

Can anyone help me pls!!! I would just like to have a list of hospitals which are scrollable. Thank you! The URL of the Json is here: https://cz2006api.herokuapp.com/api/getAll

Upvotes: 0

Views: 110

Answers (3)

Linda Paiste
Linda Paiste

Reputation: 42218

I agree with @Nguyễn's suggestion that your initial state should be an array. However the root of the issue seems to be getting the right properties off off your JSON response.

First, you want responseJson.data instead of responseJson.data.data. That gives me an array and shows a long list but the titles are all blank. That's because your response has Name as an uppercase property but you are accessing name. So you need to change that as well.

export default class ClinicComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      dataSource: [],
    };
  }

  componentDidMount() {
    return fetch('https://cz2006api.herokuapp.com/api/getAll')
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({
          isLoading: false,
          dataSource: responseJson.data,
        });
      })
      .catch((error) => {
        console.log(error);
      });
  }
  render() {
    //console.log(this.state.dataSource?.[0]);
    if (this.state.isLoading) {
      return (
        <View style={styles.container}>
          <ActivityIndicator />
        </View>
      );
    } else {
      return (
        <View style={styles.item}>
          {/* <Text>Content Loaded</Text> */}
          {this.state.dataSource.map((val, key) => (
            <View key={val._id} style={styles.item}>
              <Text>{val.Name}</Text>
            </View>
          ))}
        </View>
      );
    }
  }
}

You are fetching a huge amount of data and you probably want some sort of pagination with infinite scrolling. It is extremely slow to load due to the huge payload that we are fetching.

You also have double-escape problem in the JSON response inside the geocodingData section. You want to return this data as an object but it is an escaped string with lots of \" instead.

Upvotes: 0

Nguyễn Khương
Nguyễn Khương

Reputation: 371

Simply change your initial state to something like this

    this.state = {
      isLoading: true,
      dataSource: [],  // <-- here
    };

Your problem is you're using dataSource.map but during api calling your dataSource still stay null until it get its response, and null object have no attribute map. That's the cause of your problem.

Upvotes: 1

Wen W
Wen W

Reputation: 2647

remove the return in componentDidMount:

componentDidMount() {
    fetch("https://cz2006api.herokuapp.com/api/getAll")
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({
          dataSource: responseJson.data.data,
          isLoading: false,
        });
      })
      .catch((error) => {
        console.log(error);
      });
  }

Upvotes: 0

Related Questions