ReactJS: Calculate average from array of strings in JSON object during render

Viewed 3587

My First Application with ReactJS

I have no prior experience with reactjs and json, but am trying to increase my skill set and have been told reactjs is great for front end.

I am attempting to read an call an API, get a json object, parse it and display certain information. I am able to achieve almost all of this with relative ease with the help of several online tutorials, but I have hit a wall.

Issue:
I have parsed and displayed the majority of the json object but there is an array of strings in each object. I would like to take the average of that array from the json object and display that in html as well. Below is my attempt:

//importing necessary modules
import React from 'react';
import ReactDOM from 'react-dom';

//class creates the React component I am building
class ContentFeed extends React.Component {
   constructor() {
     super();

     this.state = {
       'workers': []
     }
   }

   componentDidMount() {
     this.getItems();
   }

   getItems() {
     fetch('localhost:7575')
       .then(results => results.json())
       //.then(results => console.log(results));
       .then(results => this.setState({'workers': results.workers}));
   }

   render() {
     return (            
       <ul>
         // I'm quite new to reactjs 
         // so I'm not too sure if what I'm doing below is legal syntax
         {this.state.workers.map(function(item, index) {
             var arrNum = 0;    
             var h = item.hours.split(",");
             var sum = 0;
             for(var i = 0; i < h.length; i++) {
                sum += parseInt(h[i]);
             }
             arrNum = (sum/h.length);    
             return (
                <div key={index}>
                  <h1>{item.firstName} {item.lastName}</h1>
                  <h4>{item.hireDate}</h4>
                  <h4>{item.dept}</h4>
                  <h4>arrNum</h4>
                </div>
              )
          })}
       </ul>
     );
   }
}

ReactDOM.render(
    <ContentFeed/>,
    document.getElementById('root')
);

What should appear is an html page with a header that contains the employees name followed by smaller headers containing the relevant employee info followed by an avg of their work hours.

However the webpage is blank.

I have checked the console tab in the developer's tools on the page and have seen an error like this:

Uncaught TypeError: item.hours.split is not a function
    at index.js:29
    at Array.map (<anonymous>)
    at ContentFeed.render (index.js:26)
    at finishClassComponent (react-dom.development.js:17160)
    at updateClassComponent (react-dom.development.js:17110)
    at beginWork (react-dom.development.js:18620)
    at HTMLUnknownElement.callCallback (react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
    at invokeGuardedCallback (react-dom.development.js:292)
    at beginWork$1 (react-dom.development.js:23203)

I am unsure how to resolve this. I sincerely hope I have provided as much relevant information as needed. Thank you for any help.

UPDATE 1

This is from the console tab

Uncaught TypeError: item.hours.split is not a function
    at index.js:29
    at Array.map (<anonymous>)
    at ContentFeed.render (index.js:26)
    at finishClassComponent (react-dom.development.js:17160)
    at updateClassComponent (react-dom.development.js:17110)
    at beginWork (react-dom.development.js:18620)
    at HTMLUnknownElement.callCallback (react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
    at invokeGuardedCallback (react-dom.development.js:292)
    at beginWork$1 (react-dom.development.js:23203)

UPDATE 2

This is some of the raw JSON from fetch

{
"workers": [
{
"firstName": "Tom",
"lastName": "Ronson",
"dept": "Sales",
"hireDate": "09/09/2015",
"hours": [
"8",
"10",
"4",
"6",
"6"
]
},
{
"firstName": "Bob",
"lastName": "Howser",
"dept": "Acct",
"hireDate": "01/05/2005",
"hours": [
"8",
"10",
"4",
"6",
"6"
]
},
{
"firstName": "Jane",
"lastName": "Winger",
"dept": "Legal",
"hireDate": "08/01/2008",
"hours": [
"5",
"6",
"5",
"5",
"6"
]
},
2 Answers

Your response data's hours property is an array of strings, not a comma separated list of hours as a string.

workers: [
  {
    firstName: "Tom",
    lastName: "Ronson",
    dept: "Sales",
    hireDate: "09/09/2015",
    hours: ["8", "10", "4", "6", "6"]
  },
  {
    firstName: "Bob",
    lastName: "Howser",
    dept: "Acct",
    hireDate: "01/05/2005",
    hours: ["8", "10", "4", "6", "6"]
  },
  {
    firstName: "Jane",
    lastName: "Winger",
    dept: "Legal",
    hireDate: "08/01/2008",
    hours: ["5", "6", "5", "5", "6"]
  }
]

The average hours worked can be computed using an array::reduce to compute a sum of hours divided by the array length

const avg =
    item.hours.reduce((sum, curr) => sum + Number(curr), 0) /
    item.hours.length;

You can map the data as such (don't forget to use correct JSX syntax, i.e. <h4>{avg}</h4> versus <h4>avg</h4>)

{this.state.workers.map((item, index) => {
  const avg =
    item.hours.reduce((sum, curr) => sum + Number(curr), 0) /
    item.hours.length;

  return (
    <li key={index}>
      <h1>
        {item.firstName} {item.lastName}
      </h1>
      <h4>{item.hireDate}</h4>
      <h4>{item.dept}</h4>
      <h4>{avg}</h4> // <-- * use correct JSX syntax
    </li>
  );
})}

Edit reactjs-calculate-average-from-array-of-strings-in-json-object-during-render

there is an array of strings in each JSON object. I would like to take the average of that array

From your description, item.hours is an array of strings. But in your code

item.hours.split(",");

You treat it like a single, comma-separated, string.

Given you're getting TypeError, it seems it is in fact an array of strings (preferably you'd update your question with sample data).

To get the average of an array, you can use reduce:

  const avg = item.hours.reduce((a,b) => a + parseFloat(b),0) / item.hours.length;
Related