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