bruce
bruce

Reputation: 463

Passing props and mapping data in React

I'm working on a project that requires me to pass data to two functional components.

My axios call to the API seems to work, as well as setting the state with hooks, but I keep receiving these two errors:

  1. Error Cannot convert undefined or null to object I tried checking if the array is empty but that didn't seem to solve the problem
  2. summaryMetrics is not defined - This I don't understand because summartMetrics is defined. Could it be that the elements are being displayed before the data is fetched ?

Here are the files in a codesandbox Included the API's so people can see the structure of how the JSON is being returned. Im not sure if I'm passing and mapping the data correctly.

enter image description here

enter image description here

Here are the files in a codesandbox

Any help is very much appreciated

Upvotes: 0

Views: 796

Answers (3)

Florian Motteau
Florian Motteau

Reputation: 3714

Since your state has this form :

const [summary, setSummaryData] = useState({
  summaryMetrics: null,
  platformsData: null
});

...you should access your state like this :

<SummaryMetrics
  uniqueSocialMediaPost={summary.summaryMetrics[0]["uniqueSocialMediaPost"]}
  positiveScore={summary.summaryMetrics[0]["positiveScore"]}
  riskScore={summary.summaryMetrics[0]["riskScore"]}
/>

[...]

Note the "summary." before "summaryMetrics" :

summary.summaryMetrics[0]["uniqueSocialMediaPost"]

Fixed Fixed Code Sandbox (other things seems to go wrong though, white screen, but syntax error is fixed) :

Edit keen-goldwasser-fhj8j

Previous errors were :

  • mocky.io serves content over HTTP, Code Sandbox over HTTPS so mixed content issue : Chrome does not allow this kind of mix in protocols, fixed by using HTTPS protocol to grab infos from mocky.io,
  • no unique keys for SummaryByPlatform component in map function

Chrome dev tools is your friend when nothing happens as expected :).

By the way you could just

summary.summaryMetrics.map(s => <SummaryByPlatform summaryMetrics={s} />)

...instead of gettings keys, and you could simply pass whole summaryMetrics object to SummaryByPlatform and have only one props. But that's another subject.

Good luck with it.

Upvotes: 1

yqlim
yqlim

Reputation: 7080

There are several problems:

  1. summaryMetrics is indeed not defined. It was actually defined as summary.summaryMetrics.
  2. summary.summaryMetrics[0][...] will cause another "undefined error", because it was defined with default value of null.

Explanation for Problem 1:

No further explanation needed.

Explanation for Problem 2:

useEffect in React functional component will only be run after the component is being rendered.

This means that when you execute summary.summaryMetrics[0][...], summary.summaryMetrics is actually null because you defined it as the default value. Therefore, the steps behind will generate another error because null[0] is not possible.

What you need to do is to check whether each object properties down the tree is actually a valid object before you call the property. Otherwise, the error will happen down the property tree.

I can't show you how to correct your code, because I would need to change a big part of you code. What you can try is to mainly check the presence of values of summary.summaryMetrics first, before calling it's children properties.

Upvotes: 0

mnsr
mnsr

Reputation: 12437

Your issue is that you're not waiting for summaryMetrics to load. It's trying to read the array before it's been fetched.

What I would do, is put the render inside a function and conditionally load it once the data is available.

So your Summary.js file would look like this:


  const renderSummaryMetrics = () => 
    summary && 
    summary.summaryMetrics && (
    <div>
      <SummaryMetrics
        uniqueSocialMediaPost={summary.summaryMetrics[0]["uniqueSocialMediaPost"]}
        positiveScore={summary.summaryMetrics[0]["positiveScore"]}
        riskScore={summary.summaryMetrics[0]["riskScore"]}
      />
      {Object.keys(summary.summaryMetrics) &&
      Object.keys(summary.summaryMetrics).length > 0
        ? Object.keys(summary.summaryMetrics).map(keyName => (
            <SummaryByPlatform
              platform={keyName}
              mean_sentiment={summary.summaryMetrics[keyName].mean_sentiment}
              post_count={summary.summaryMetrics[keyName].post_count}
              positive_posts={summary.summaryMetrics[keyName].positive_posts}
              negative_posts={summary.summaryMetrics[keyName].negative_posts}
            />
          ))
        : null}
    </div>);

    return renderSummaryMetrics();

Upvotes: 0

Related Questions