Skip to content
Advertisement

How do I loop through a JSON array with React Native?

I’ve recently started on a React Native project and have been struggling with mapping JSON objects A LOT. I’ve looked through a lot of posts but have received the same error each time.

Below is a few snippets of the code I’m working with on mapping the JSON

  getUserNotifications = () => {
    var uname = this.state.userName;
    fetch('https://examp.le/endpoint?getNotifications&username=' + uname) // api url
    .then((response) => response.json())
    .then((responseJson) => {
          this.setState({notifications: responseJson});
          console.log("Notification response:" + this.state.notifications);
        //   alert(responseJson);
          }).catch((error) => {
            console.error(error);
          });
  }

Which returns something like the JSON snippet below

[
   {
      "data":{
         "from":"user",
         "time":"13 hours ago",
         "fromPfp":"users/287/avatar/application_1588872189.jpg",
         "type":"commentLike"
      }
   },
   {
      "data":{
         "from":"user",
         "time":"13 hours ago",
         "fromPfp":"users/287/avatar/application_1588872189.jpg",
         "type":"comment_mention"
      }
   }
]

Here’s my mapping code

        {this.state.notifications.data.map(data => (
                <View style= {{ display: "flex", flex: 1, flexDirection: "row", backgroundColor: "#2a2a2a", padding: 15 }}>
                    <Text style={{ color: "#fff", fontSize: 12, display: "flex", flexDirection: "row", marginTop: 6, marginLeft: 8 }}>{data.from} liked your post</Text>
                </View>
                <Text style={{ color: "#ddd", fontSize: 9, display: "flex", flexDirection: "column", marginLeft: 18, marginBottom: 20 }}>{data.time}</Text>
            </View>  
        ))}

I keep receiving TypeError: undefined is not an object (evaluating 'this.state.notifications.data.map') as my error.

— snippets —

Notification response in getUserNotifications displays this in console:

Notification response:[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

JSON.stringify in render:

json after the render is finished: [
   {
      "from":"user",
      "time":"2 hours ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"like"
   },
   {
      "from":"user",
      "time":"2 hours ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"like"
   },
   {
      "from":"user",
      "time":"20 hours ago",
      "fromPfp":"users/287/avatar/application_1588872189.jpg",
      "type":"commentLike"
   },
   {
      "from":"user",
      "time":"20 hours ago",
      "fromPfp":"users/287/avatar/application_1588872189.jpg",
      "type":"commentLike"
   },
   {
      "from":"user",
      "time":"20 hours ago",
      "fromPfp":"users/287/avatar/application_1588872189.jpg",
      "type":"comment_mention"
   },
   {
      "from":"user",
      "time":"20 hours ago",
      "fromPfp":"users/291/avatar/application_1593241576.jpg",
      "type":"comment_mention"
   },
   {
      "from":"user",
      "time":"21 hours ago",
      "fromPfp":"users/271/avatar/application_1592193853.jpg",
      "type":"like"
   },
   {
      "from":"user",
      "time":"21 hours ago",
      "fromPfp":"users/271/avatar/application_1592193853.jpg",
      "type":"like"
   },
   {
      "from":"user",
      "time":"21 hours ago",
      "fromPfp":"users/271/avatar/application_1592193853.jpg",
      "type":"like"
   },
   {
      "from":"user",
      "time":"21 hours ago",
      "fromPfp":"users/271/avatar/application_1592193853.jpg",
      "type":"like"
   },
   {
      "from":"user",
      "time":"21 hours ago",
      "fromPfp":"users/271/avatar/application_1592193853.jpg",
      "type":"post"
   },
   {
      "from":"user",
      "time":"1 day ago",
      "fromPfp":"users/291/avatar/application_1593241576.jpg",
      "type":"comment_mention"
   },
   {
      "from":"user",
      "time":"1 day ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"comment_mention"
   },
   {
      "from":"user",
      "time":"1 day ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"like"
   },
   {
      "from":"user",
      "time":"1 day ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"like"
   },
   {
      "from":"user",
      "time":"2 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"post"
   },
   {
      "from":"user",
      "time":"2 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"like"
   },
   {
      "from":"user",
      "time":"2 days ago",
      "fromPfp":"users/287/avatar/application_1588872189.jpg",
      "type":"comment_mention"
   },
   {
      "from":"user",
      "time":"2 days ago",
      "fromPfp":"users/287/avatar/application_1588872189.jpg",
      "type":"commentLike"
   },
   {
      "from":"user",
      "time":"3 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"like"
   },
   {
      "from":"user",
      "time":"4 days ago",
      "fromPfp":"users/287/avatar/application_1588872189.jpg",
      "type":"like"
   },
   {
      "from":"user",
      "time":"4 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"post"
   },
   {
      "from":"user",
      "time":"5 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"post"
   },
   {
      "from":"user",
      "time":"6 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"post"
   },
   {
      "from":"user",
      "time":"6 days ago",
      "fromPfp":"users/270/avatar/application_1588987915.png",
      "type":"post"
   }
]

Errors

Warning: Each child in a list should have a unique "key" prop.%s%s See LINK for more information.%s, 

Check the render method of `NotifsScreen`., , 
    in Unknown (at NotifsScreen.js:201)

The following error repeats itself 25 times:

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s%s, undefined,  You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports

Check your code at NotifsScreen.js:201.

Line 201 is the first


import React, { Component, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { ActivityIndicator, Image, ScrollView, Text, View, TouchableOpacity, TextInput, RefreshControl, Fragment } from 'react-native';
import { NavigationEvents, useTheme } from 'react-navigation';
import { gStyle, colors } from '../constants';

// import { userInfo } from './HomeScreen';
import AsyncStorage from '@react-native-community/async-storage'



class NotifsScreen extends Component {
  constructor(props){
    super(props);
    this.state = {
      userName: '',
      firstName: '',
      lastName: '',
      bio: '',
      followers: '',
      following: '',
      postcount: '',
      avatar: '',
      verified: '',
      response: '',
      notifications: ''
    };
  }

  
  getUserNotifications = () => {
    var uname = this.state.userName;
    var uname = uname.replace(/"/g, "")
    fetch('https://examp.le/endpoint?getNotifications&username=' + uname) // api url
    .then((response) => response.json())
    .then((responseJson) => {
          let newArr = [];

          for (const item of responseJson) {
            newArr.push(item.data);
          }
          this.setState({notifications: newArr});
          console.log("Notification response: " + this.state.notifications);
        //   alert(responseJson);
          }).catch((error) => {
            console.error(error);
          });
  }

  // async component did mount (basically the same as document did load)
  async componentDidMount() {  
      console.log("Component mounted on notifications");
    
    try{
      let value = await AsyncStorage.getItem("userName");
      let firstname = await AsyncStorage.getItem("firstName");
      let lastname = await AsyncStorage.getItem("lastName");
      let bio = await AsyncStorage.getItem("bio");
      let followers = await AsyncStorage.getItem("followerCount");
      let following = await AsyncStorage.getItem("followingCount");
      let postcount = await AsyncStorage.getItem("postCount");
      let avatar = await AsyncStorage.getItem("avatar");
      let verified = await AsyncStorage.getItem("verified");
      if(verified !== undefined) { 
        this.setState({ userName: value, avatar: avatar, firstName: firstname, lastName: lastname, followers: followers, following: following, postcount: postcount, verified: verified, bio: bio }, function () {   });
      } else {
        this.setState({ userName: value, avatar: avatar, firstName: firstname, lastName: lastname, followers: followers, following: following, postcount: postcount, verified: "no", bio: bio }, function () {   });
      }
      console.log("USER SET: " + value + " ON NOTIFICATIONS");
      console.log("Attempting to get notifications...");
      this.getUserNotifications();
      // return value.json();
    }
  catch(e){
      console.log('caught error', e);
      // Handle exceptions
  }
  }

  refreshGetUserInfo = () =>{
    // Simple GET request using fetch
    var username = this.state.userName;
    var username = username.replace(/"/g, "")
    fetch('https://examp.le/endpoint?username=' + username) // api url
      .then((response) => response.json())
      .then((responseJson) => {
        AsyncStorage.setItem("userName", responseJson.userName)
        AsyncStorage.setItem("firstName",responseJson.firstName)
        AsyncStorage.setItem("lastName", responseJson.lastName)
        AsyncStorage.setItem("bio", responseJson.bio)
        AsyncStorage.setItem("postCount", responseJson.postCount)
        AsyncStorage.setItem("followerCount", responseJson.followerCount)
        AsyncStorage.setItem("followingCount", responseJson.followingCount)
        AsyncStorage.setItem("verified", responseJson.verified)
        AsyncStorage.setItem("moderator", responseJson.moderator)
        AsyncStorage.setItem("avatar", responseJson.avatar)
        
        console.log("[L1] Successfully got information from profile page.");

          // the code below is a working json example
  
          // now i'm going to add the array to async storage so that i will be able to access this data
          // from other screens.


          let value = AsyncStorage.getItem("userName");
          let firstname = AsyncStorage.getItem("firstName");
          let lastname = AsyncStorage.getItem("lastName");
          let bio = AsyncStorage.getItem("bio");
          let followers = AsyncStorage.getItem("followerCount");
          let following = AsyncStorage.getItem("followingCount");
          let postcount = AsyncStorage.getItem("postCount");
          let avatar = AsyncStorage.getItem("avatar");
          let verified = AsyncStorage.getItem("verified");
          if(verified !== undefined) { 
            this.setState({ userName: value, avatar: avatar, firstName: firstname, lastName: lastname, followers: followers, following: following, postcount: postcount, verified: verified, bio: bio }, function () {   });
          } else {
            this.setState({ userName: value, avatar: avatar, firstName: firstname, lastName: lastname, followers: followers, following: following, postcount: postcount, verified: "no", bio: bio }, function () {   });
          }
          console.log("USER SET: " + value + " ON NOTIFICATIONS");
          // return value.json();
          var uname = this.state.userName;
          var uname = uname.replace(/"/g, "")
            this.props.navigation.setParams({
              Title: uname,
              Badge: this.state.verified
          });
          this.setState({refreshing: false}); 


        })
  }

  onRefresh() {
    // get latest data
    // this.refreshGetUserInfo();
    this.setState({refreshing: false}); 
  }


  static navigationOptions = ({ navigation }) => {
        return {
          headerTitleStyle: gStyle.headerTitleStyle,
          headerTitle: (
            <View style={{ flex: 1, flexDirection: "row", alignItems: 'center', justifyContent: 'center' }}>
              <Text style={{ color: "#ffffff", fontSize: 16, fontWeight: 'bold', marginRight: 5 }}>Notifications</Text>                
            </View>
          ),
          headerStyle: {
            backgroundColor: colors.darkColor,
            color: colors.white20,
            borderBottomColor: colors.darkColor,
          }
        };

  };


  render() {
    const user = this.state.userName;
    const avatar = "https://examp.le/" + this.state.avatar;
    var fixedAvatar = avatar.replace(/"/g, "");
    var fname = this.state.firstName;
    var fname = fname.toString().replace(/"/g, "")
    var lname = this.state.lastName;
    var lname = lname.toString().replace(/"/g, "")
    var uname = this.state.userName;
    var uname = uname.toString().replace(/"/g, "")
    var bio = this.state.bio;
    var bio = bio.toString().replace(/"/g, "")
    var json = JSON.stringify(this.state.notifications);
    console.log("json after the render is finished: " + JSON.stringify(this.state.notifications));
    if (!this.state.notifications) {
      return <View                  
      contentContainerStyle={gStyle.contentContainer}
      style={gStyle.container.dark}
      /> 
   }
  return (
    <ScrollView
      contentContainerStyle={gStyle.contentContainer}
      style={gStyle.container.dark}
      refreshControl={
        <RefreshControl refreshing={this.state.refreshing} onRefresh={this.onRefresh.bind(this)} />
      }>
      {/* <Text>{JSON.stringify(this.state.notifications)}</Text> */}

      {
  this.state.notifications.map((data) => (
    <Fragment>
      <View
        style={{
          display: "flex",
          flex: 1,
          flexDirection: "row",
          backgroundColor: "#2a2a2a",
          padding: 15,
        }}
      >
        <Text
          style={{
            color: "#fff",
            fontSize: 12,
            display: "flex",
            flexDirection: "row",
            marginTop: 6,
            marginLeft: 8,
          }}
        >
          {data.from} liked your post
        </Text>

        <Text
          style={{
            color: "#ddd",
            fontSize: 9,
            display: "flex",
            flexDirection: "column",
            marginLeft: 18,
            marginBottom: 20,
          }}
        >
          {data.time}
        </Text>
      </View>
    </Fragment>
  ))
}
    </ScrollView>
  );
};
}



export default NotifsScreen;

Advertisement

Answer

Can you try this

import React, { Component, useEffect, useState, Fragment } from 'react';
..... 


{
  this.state.notifications.map((data) => (
    <Fragment>
      <View
        style={{
          display: "flex",
          flex: 1,
          flexDirection: "row",
          backgroundColor: "#2a2a2a",
          padding: 15,
        }}
      >
        <Text
          style={{
            color: "#fff",
            fontSize: 12,
            display: "flex",
            flexDirection: "row",
            marginTop: 6,
            marginLeft: 8,
          }}
        >
          {stuff.from} liked your post
        </Text>

        <Text
          style={{
            color: "#ddd",
            fontSize: 9,
            display: "flex",
            flexDirection: "column",
            marginLeft: 18,
            marginBottom: 20,
          }}
        >
          {stuff.time}
        </Text>
      </View>
    </Fragment>
  ));
}
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement