【问题标题】:How do I loop through a JSON array with React Native?如何使用 React Native 遍历 JSON 数组?
【发布时间】:2020-08-12 20:42:14
【问题描述】:

我最近开始了一个 React Native 项目,并且一直在努力映射 JSON 对象。我浏览了很多帖子,但每次都收到相同的错误。

以下是我正在使用的一些用于映射 JSON 的代码的 sn-ps

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

返回类似于下面的 JSON sn-p 的东西

[
   {
      "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"
      }
   }
]

这是我的映射代码

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

我不断收到TypeError: undefined is not an object (evaluating 'this.state.notifications.data.map') 作为我的错误。

-- sn-ps --

getUserNotifications 中的通知响应在控制台中显示:

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:

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"
   }
]

错误

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)

以下错误会重复 25 次:

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.

第 201 行是第一行


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;

【问题讨论】:

    标签: php json reactjs react-native


    【解决方案1】:

    你可以试试这个

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

    【讨论】:

    • 运行此代码时出现以下错误:Text strings must be rendered within a &lt;Text&gt; component.
    • 类型错误至少得到解决了吗?我不确定为什么会出现该错误,因为 {stuff.from} 和 {stuff.time} 包含在 Text 组件中。你能 console.log 这个错误是从哪里来的吗?
    • 仍然出现与以前相同的错误。我尝试将此解决方案与其他解决方案一起添加,它没有抛出任何错误,但它没有返回 JSON 信息。
    • 如果您可以像上面那样重组 json,它会起作用,如果您无法更改 json,我会回来提供重新安排数据的解决方案。给我几个小时。
    • 很抱歉,甚至没有看到您想要重组。我对其进行了重组,但仍然没有得到任何回报。
    【解决方案2】:

    正如错误信息所指出的,最初 this.state.notification 是未定义的。您必须考虑到 fetch 是一个 async call 所以可能在第一次渲染期间, this.state.notification 没有填充任何信息。您可以在返回您编写的映射代码之前添加一个 console.log 来测试它。

    为确保仅在 this.state 中已填充 API 调用信息时才访问通知对象,您可以执行以下操作:

    if (!this.state.notifications) {
       return <View/> 
    }
    
    return (
       <EnterYourCodeHere/>
    )
    

    这样,如果没有来自 API 调用的通知,您将返回一个空视图。但是当收到信息时,您可以将来自它的 json 与您现有的代码进行映射。

    希望这会有所帮助!

    【讨论】:

    • 感谢您对此的回复和解释!我在渲染中添加了console.log(JSON.stringify(this.state.notifications));,它确实记录了所有的 JSON。我继续尝试了您的代码,但我不再收到该错误,它只是没有返回映射中的任何代码。
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 2021-01-07
    • 2021-09-29
    • 2018-08-26
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 2017-08-22
    相关资源
    最近更新 更多