retro
retro

Reputation: 51

Better way to extract data from HTML table and update react state?

The fetch request returns the following response https://codeshare.io/alP0Bd. The needed information is the buy/sell rate for three major currencies, so I parse the response as HTML as other users suggested and filter it. All this works but to be honest it seems a bit too laborious and repetitive. Suggestions for optimisations are welcome.

import React, { useEffect, useState } from "react";
const Rate = () => {
  const [CurrencyRates, setCurrencyRates] = useState({
    USD: {
      buy: 1.5812,
      sell: 1.6461,
    },
    EUR: {
      buy: 1.94,
      sell: 1.96,
    },
    GBP: {
      buy: 2.078,
      sell: 2.186,
    },
  });
  useEffect(() => {
    fetch(`someURL`,
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    )
      .then((response) => response.json())
      .then((result) => {
        if (result) {
          const el = document.createElement("html");
          el.innerHTML = result.table_html;
          const arr = Array.from(el.getElementsByTagName("tr"));
          const filtered = arr.filter((row) => {
            if (!row.cells[0].firstElementChild) {
              return false;
            }
            if (
              row.cells[0].firstElementChild.childNodes[1].data === " EUR" ||
              row.cells[0].firstElementChild.childNodes[1].data === " USD" ||
              row.cells[0].firstElementChild.childNodes[1].data === " GBP"
            ) {
              return true;
            }
          });

          const currency = {
            USD: {
              buy: 1.0,
              sell: 1.0,
            },
            EUR: {
              buy: 1.0,
              sell: 1.0,
            },
            GBP: {
              buy: 1.0,
              sell: 1.0,
            },
          };
          const rate = filtered.map((row) => {
            if (row.cells[0].firstElementChild.childNodes[1].data === " EUR") {
              currency.EUR.buy = row.cells[2].innerHTML;
              currency.EUR.sell = row.cells[3].innerHTML;
            }
            if (row.cells[0].firstElementChild.childNodes[1].data === " USD") {
              currency.USD.buy = row.cells[2].innerHTML;
              currency.USD.sell = row.cells[3].innerHTML;
            }
            if (row.cells[0].firstElementChild.childNodes[1].data === " GBP") {
              currency.GBP.buy = row.cells[2].innerHTML;
              currency.GBP.sell = row.cells[3].innerHTML;
              setCurrencyRates(currency);
            }
          });
        } else {
          throw new Error(result.message);
        }
      })
      .catch((error) => console.log(error.message));
  }, []);

  return (
    <tr>
      <td>Rates</td>
      <td>{CurrencyRates.USD.buy}</td>
      <td>{CurrencyRates.USD.sell}</td>
      <td>{CurrencyRates.EUR.buy}</td>
      <td>{CurrencyRates.EUR.sell}</td>
      <td>{CurrencyRates.GBP.buy}</td>
      <td>{CurrencyRates.GBP.sell}</td>
    </tr>
  );
};
export default Rate;

Upvotes: 0

Views: 200

Answers (1)

Badyanchik
Badyanchik

Reputation: 111

I didn't test it with your JSON data (looks like it's invalid).

But, I guess you can simplify it:

import React, { useEffect, useState } from "react";

const CURRENCIES = ["EUR", "USD", "GBP"];
const DEFAULT_CURRENCY = {
  USD: {
    buy: 1.0,
    sell: 1.0
  },
  EUR: {
    buy: 1.0,
    sell: 1.0
  },
  GBP: {
    buy: 1.0,
    sell: 1.0
  }
};

const getCurrencyStr = (row) =>
  (row.cells[0].firstElementChild.childNodes[1].data || "").trim();
const Rate = () => {
  const [CurrencyRates, setCurrencyRates] = useState({
    USD: {
      buy: 1.5812,
      sell: 1.6461
    },
    EUR: {
      buy: 1.94,
      sell: 1.96
    },
    GBP: {
      buy: 2.078,
      sell: 2.186
    }
  });
  useEffect(() => {
    fetch(`someURL`, {
      headers: {
        "Content-Type": "application/json"
      }
    })
      .then((response) => response.json())
      .then((result) => {
        if (result) {
          const el = document.createElement("html");
          el.innerHTML = result.table_html;
          const arr = Array.from(el.getElementsByTagName("tr"));
          const filtered = arr.filter((row) => {
            if (!row.cells[0].firstElementChild) {
              return false;
            }
            return CURRENCIES.includes(getCurrencyStr(row));
          });

          const currency = {
            ...DEFAULT_CURRENCY
          };

          filtered.forEach((row) => {
            const currentCurrency = getCurrencyStr(row);
            if (currentCurrency && currentCurrency in currency) {
              currency[currentCurrency].buy = row.cells[2].innerHTML;
              currency[currentCurrency].sell = row.cells[3].innerHTML;
            }
          });
          setCurrencyRates(currency);
        } else {
          throw new Error(result.message);
        }
      })
      .catch((error) => console.log(error.message));
  }, []);

  return (
    <tr>
      <td>Rates</td>
      {Object.values(CurrencyRates).map((currency) => {
        return (
          <React.Fragment key={currency.buy + currency.sell}>
            <td>{currency.buy}</td>
            <td>{currency.sell}</td>
          </React.Fragment>
        );
      })}
    </tr>
  );
};
export default Rate;

Upvotes: 1

Related Questions