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>
));
}