How to sum up data in the rendered component in react?

Tags: ,



I want to sum up each multiplication of weights and repeats that belong to the same trained_at string. Currently I realize the “grouping” of dates by comparing the current date string with the previous date string in the render part of my component.

In my code example that is fully working you can find a Sum here comment, where I want to render the calculation result.

My sample data is coming from Firestore in the real app and does not have that calculation. Thus I need to calculate after fetching the result.

This is what I got rendered:

_________________
20200918  |
20        |   12
20        |   12
20        |   12
_________________
20200916  |
15        |   12
15        |   12
15        |   12
________________

This is what I want to accomplish:

_________________
20200918  |  720  <--
20        |   12
20        |   12
20        |   12
_________________
20200916  |  540  <--
15        |   12
15        |   12
15        |   12
________________

And this is my code:

import React from "react";

function List() {
  /* Sample Data: */
  const set = [
    {
      id: 1,
      trained_at: "20200918",
      weights: 20,
      repeats: 12,
    },
    {
      id: 2,
      trained_at: "20200918",
      weights: 20,
      repeats: 12,
    },
    {
      id: 3,
      trained_at: "20200918",
      weights: 20,
      repeats: 12,
    },
    {
      id: 4,
      trained_at: "20200916",
      weights: 15,
      repeats: 12,
    },
    {
      id: 5,
      trained_at: "20200916",
      weights: 15,
      repeats: 12,
    },
    {
      id: 6,
      trained_at: "20200916",
      weights: 15,
      repeats: 12,
    },
  ];

  return (
    <table>
      {set.map((row, i) => {
        const previous = set[i - 1] !== undefined ? set[i - 1] : {};
        return (
          <React.Fragment key={row.id}>
            {row.trained_at !== previous.trained_at ? (
              <tr>
                <td>{row.trained_at}</td>
                <td>{/* Sum here */}</td>
              </tr>
            ) : (
              <></>
            )}
            <tr>
              <td>{row.weights}</td>
              <td>{row.repeats}</td>
            </tr>
          </React.Fragment>
        );
      })}
    </table>
  );
}
export default List;

Answer

You need to first re-group the items and calculate the sum, then display them.

import React from "react";

function groupAndCalc(data) {
  const map = data.reduce((acc, item) => {
    const key = item.trained_at;
    let group = acc.get(key);
    if (!group) {
      group = { trained_at: key, sum: 0, items: [] };
      acc.set(key, group);
    }

    group.items.push(item);
    group.sum += item.weights * item.repeats;
    
    return acc;
  }, new Map());

  return Array.from(map.values());
}

function List() {
  /* Sample Data: */
  const set = [
    {
      id: 1,
      trained_at: "20200918",
      weights: 20,
      repeats: 12,
    },
    {
      id: 2,
      trained_at: "20200918",
      weights: 20,
      repeats: 12,
    },
    {
      id: 3,
      trained_at: "20200918",
      weights: 20,
      repeats: 12,
    },
    {
      id: 4,
      trained_at: "20200916",
      weights: 15,
      repeats: 12,
    },
    {
      id: 5,
      trained_at: "20200916",
      weights: 15,
      repeats: 12,
    },
    {
      id: 6,
      trained_at: "20200916",
      weights: 15,
      repeats: 12,
    },
  ];

  return (
    <table>
      {groupAndCalc(set).map((group) => {
        return (
          <React.Fragment key={group.trained_at}>
            <tr>
              <td>{group.trained_at}</td>
              <td>{group.sum}</td>
            </tr>
            {group.items.map((row) => (
              <tr key={row.id}>
                <td>{row.weights}</td>
                <td>{row.repeats}</td>
              </tr>
            ))}
          </React.Fragment>
        );
      })}
    </table>
  );
}
export default List;


Source: stackoverflow