I am trying to make a react component that returns the average number after fetching the data from the DB and converting it to json.
Total novice here. I am trying to make a react component that returns the average number after fetching the data from the DB and converting it to json. This is the json I am working with, which is fetched succesfully, but I am not sure how to do the calculation in react. Basically I am trying to get the average from all the numbers in the field "ivertinimai".
This is the component:
import React, { useState, useEffect, useContext, useRef } from 'react';
const AverageEvaluation = (props) => {
let [allEvaluations, setAllEvaluations] = useState()
let [evaluationsArray, setEvaluationsArray] = useState([])
let [sum, setSum] = useState(0)
let [average, setAverage] = useState(0)
useEffect(() => {
fetch("http://127.0.0.1:8000/api/getevaluations/" + props.mealId, {method: 'GET', headers: { 'Content-Type': 'application/json' }})
.then(response => response.json())
.then(response=>{setAllEvaluations(allEvaluations=response); console.log(response)})
}, []);
let getAverage = () => {
allEvaluations.map((meal, index)=>setEvaluationsArray([...evaluationsArray, meal.ivertinimai]))
setSum(evaluationsArray.reduce((a,v) => a = a + v, 0 ))
setAverage(average = sum/evaluationsArray.length)
}
return (
<>
{average}
</>
);
};
The component doesn't seem to return any result after I import and add it in another component. I'm not sure if the problem is in the function to calculate the average or is it that I am trying to use react in the wrong way here. Would appreciate your help.
There are a few things I see that need a change:
It should be const [ ..., ... ] = ...
not let [..., ...]
I would put an empty array into initial declaration of allEvaluations
-> useState([]);
setAllEvaluations(allEvaluations=response)
and setAverage(average = sum/evaluationsArray.length)
should be setAllEvaluations(response)
and setAverage(sum/evaluationsArray.length)`
Variables allEvaluations
and average
should not be changed, so writing avegare = ...
is not only incorrect but also if written in set functions will not result in changing their values. That's because you are not putting there a new value but an assignment to a variable.
Similarly in reduce((a,v) => a = a + v, 0 )
, just write reduce((a,v) => a + v, 0 )
- no assignment needed.
getAverage
function.Firstly, instead of
allEvaluations.map((meal, index)=>setEvaluationsArray([...evaluationsArray, meal.ivertinimai]));
setSum(evaluationsArray.reduce((a,v) => a = a + v, 0 ));
setAverage(average = sum/evaluationsArray.length);
try something like this:
const newEvaluationsArray = allEvaluations.map((meal) => meal.ivertinimai);
setEvaluationsArray(newEvaluationsArray);
const newSum = newEvaluationsArray.reduce((a,v) => a + v, 0 );
setSum(newSum);
setaverage(newSum/newEvaluationsArray.length);
In the map function you wrote, you needlessly call setEvaluationsArray
for each meal object and needlessly create new and new arrays ([...evaluationsArray, meal.ivertinimai]
).
Then in your setSum
and setAverage
, you are using the useState variable (evaluationsArray)
which you have just modified. I would not recommend doing this, as when I did it sometimes there was still the old value, not the just updated one. (I'm not sure about the inner workings of useState and why/when is it happening, but I prefer to be cautious).
The same applies for sum
and setAverage
.
In my code, I first map allEvaluations
and then assign them to a constant. This creates just one new array instead of multiple. This also makes it so that you can both set the new value in setEvaluationsArray
and be sure in setSum
that it is the new value you wanted. I did a similar thing with newSum
.
Secondly, you aren't calling your getAverage
function anywhere. There are multiple options for you. Probably the easiest option is to put it in useEffect
after setAllEvaluations(response);
You will have to change getAverage
function to accept arguments, for the same reason we made newEvaluationsArray
and newSum
above:
const getAverage = (response) => {
const newEvaluationsArray = response.map((meal) => meal.ivertinimai);
setEvaluationsArray(newEvaluationsArray);
const newSum = newEvaluationsArray.reduce((a,v) => a + v, 0 );
setSum(newSum);
setaverage(newSum/newEvaluationsArray.length);
}
At this point, you could just rewrite the body of getAverage
into the useEffect
and remove getAverage
, if this is the only place where you will call it.
Hope it helps, good luck!