简体   繁体   中英

React - stuck on filtering JSON data based on whether object key exists

First post. I'm returning to web dev and programming after 10 years of being a network engineer, and I'm making a project app in React. I've run into some issues working with JSON data I've fetched from an API.

What my code does: As I mentioned, I'm using React to create this web app. I have a Search.js component which takes a username input from a form and performs a fetch operation, querying the PUBG API ((PLAYERUNKNOWNS Battlegrounds).

It then passes the JSON data it gets back via props to a Results.js function. Here's the code for that:

import React, { Component } from 'react';
import '../App.sass';
import '../index.css';

class Results extends Component {

render() {

    let content;

    if (this.props.loading) {
        content = <div className="results-container"><div className="results">
        <img src={require('../images/ajax-loader.gif')} /></div></div>
    } else {
        content =
        <div>
            <ul>
                {this.props.mData.map((matches, index) => {
                return <div className="results-container"><div className="results" key={index}>
                        <p>{matches.attributes.stats.name}</p>

              </div></div>
        })}
            </ul>
        </div>
    }


return (
    <>
    {content}
    </>

)


    }
}

export default Results;

Here is an example of the JSON data that's being passed via props:

 "mData": [
    {
      "type": "participant",
      "id": "72b04727-0ab4-4016-9468-2e10a3dbdaeb",
      "attributes": {
        "stats": {
          "DBNOs": 1,
          "assists": 0,
          "boosts": 5,
          "damageDealt": 253.54834,
          "deathType": "byplayer",
          "headshotKills": 1,
          "heals": 13,
          "killPlace": 26,
          "killStreaks": 1,
          "kills": 1,
          "longestKill": 35.026,
          "name": "Pembo",
          "playerId": "account.75b1fc48f40b4043b1eb17f2d46a8e1d",
          "revives": 0,
          "rideDistance": 7201.147,
          "roadKills": 0,
          "swimDistance": 0,
          "teamKills": 0,
          "timeSurvived": 1673.926,
          "vehicleDestroys": 0,
          "walkDistance": 3010.6506,
          "weaponsAcquired": 4,
          "winPlace": 3
        },
        "actor": "",
        "shardId": "steam"
      }
    },
    {
      "type": "participant",
      "id": "99481652-ec74-41b2-b3a3-fdab30c04b93",
      "attributes": {
        "stats": {
          "DBNOs": 1,
          "assists": 0,
          "boosts": 1,
          "damageDealt": 100,
          "deathType": "byplayer",
          "headshotKills": 0,
          "heals": 0,
          "killPlace": 42,
          "killStreaks": 1,
          "kills": 1,
          "longestKill": 11.017569,
          "name": "Mccarry79",
          "playerId": "account.e086fc7caef24e388b158cacb4dff538",
          "revives": 0,
          "rideDistance": 0,
          "roadKills": 0,
          "swimDistance": 0,
          "teamKills": 0,
          "timeSurvived": 330.793,
          "vehicleDestroys": 0,
          "walkDistance": 459.02472,
          "weaponsAcquired": 3,
          "winPlace": 26
        },
        "actor": "",
        "shardId": "steam"
      }
    },

All I'm trying to do is iterate over each object in the array and pull out the name value from attributes.stats.name, then display it on the page. The above code resulted in an error:

TypeError: Cannot read property 'name' of undefined

At this point I realised that some objects exist in this array which do not actually contain the attributes.stats.name property:

    {
      "type": "roster",
      "id": "a20c3b6c-5409-4bf6-9f04-58a08d5cd3b8",
      "attributes": {
        "stats": {
          "rank": 22,
          "teamId": 11
        },
        "won": "false",
        "shardId": "steam"
      },
      "relationships": {
        "team": "Object",
        "participants": "Object"
      }
    },

Question 1: is this the reason for the error I'm seeing? It's iterating through them all, then it hits one of the multiple objects without that property and errors?

Question 2: how do I fix this?

My first thought was that I need to filter out all the objects in the array without the property I'm looking for, so I researched that. I've tried various combinations of code, none of which have worked.

My current idea is that I want to use .filter() on the array, matching only objects which contain the key of attributes.stats.name. Nothing I've tried has managed to work, however. I've been working on this over the last few days and I'm stumped, so I'm asking for help.

Any advice is really appreciated.

...

{this.props.mData && Array.isArray(this.props.mData) && this.props.mData.map((matches, index) => {
         return <div className="results-container">
                  <div className="results" key={index}>
                    <p>{matches.attributes.stats.name}</p>
...

Try this.

Array.filter() sounds like a good method to achieve what you want in this case. The error you get (TypeError: Cannot read property 'name' of undefined) is because the "stats" property doesn't seem to exist (ie is undefined).

A filter that checks for stats and stats.name might fix this. Something like this ( el is short for element) (warning: untested code):

filteredArray = this.props.mData.filter(el => el.attributes.stats && el.attributes.stats.name);

If el.attributes.stats is falsy (undefined) it will return false immediately. If it exists, but the next check el.attributes.stats.name is falsy, it will return false. If stats exists and stats.name also exists, it will return true and the current el will be included in your results.

Then use filteredArray.map() in your jsx (instead of this.props.mData.map() ) to show the data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM