This demo focuses on using the react charting library recharts and the data grid library react-data-grid to display and chart spreadsheet data using only a single shared piece of state. The data in this demo will has the following shape:

interface Row {
  year: number;
  revenue: number;
  costs: number;
  profit: number;
}

The data is first read from a remote excel file, transformed into an array of objects with an additional key profit derived from the revenue and costs, and then saved into state.

useEffect(() => {
    const fetchData = async () => {
      const f = await (
        await fetch("http://localhost:8000/data.xlsx")
      ).arrayBuffer();
      const wb = read(f);
      const ws = wb.Sheets[wb.SheetNames[0]];
      const rawData = utils.sheet_to_json(ws);

      const newData = rawData.map((d: any) => ({
        ...d,
        profit: d.revenue - d.costs,
      }));

      setData(newData);
    };
    fetchData();
  }, []);

The data can then be rendered by both react-data-grid and recharts.

<ReactDataGrid
  columns={[
  { key: "year", name: "Year" },
  { key: "revenue", name: "Revenue", editor: textEditor },
  { key: "costs", name: "Costs", editor: textEditor },
  { key: "profit", name: "Profit" },
  ]}
  rows={data}
  onRowsChange={updateRows}
/>

In the ReactDataGrid, updateRows is used to update the state if the user changes any of the values in the editable columns, also recalculating profit based on the updated values.

  const updateRows = (rows: Row[]) => {
    setData(
      rows.map((d) => ({
        ...d,
        profit: d.revenue - d.costs,
      }))
    );
  };

Recharts displays the data in a line chart, staying in sync with the data and rerendering if the rows are updated.

<LineChart width={600} height={300} data={data}>
  <Tooltip />
  <Line type="monotone" dataKey="revenue" stroke="#8884d8" />
  <Line type="monotone" dataKey="costs" stroke="#fd41f9" />
  <Line type="monotone" dataKey="profit" stroke="#fe1f1a" />
  <XAxis dataKey="year" />
  <YAxis />
</LineChart>
import { useEffect, useState } from "react";
import ReactDataGrid, { textEditor } from "react-data-grid";
import { LineChart, Line, XAxis, YAxis, Tooltip } from "recharts";
import { read, utils, writeFileXLSX } from "xlsx";
import "./App.css";
import "react-data-grid/lib/styles.css";

interface Row {
  year: number;
  revenue: number;
  costs: number;
  profit: number;
}

function App() {
  const [data, setData] = useState<Row[]>([]);

  useEffect(() => {
    const fetchData = async () => {
      const f = await (
        await fetch("http://localhost:8000/data.xlsx")
      ).arrayBuffer();
      const wb = read(f);
      const ws = wb.Sheets[wb.SheetNames[0]];
      const rawData = utils.sheet_to_json(ws);

      const newData = rawData.map((d: any) => ({
        ...d,
        profit: d.revenue - d.costs,
      }));

      setData(newData);
    };
    fetchData();
  }, []);

  const updateRows = (rows: Row[]) => {
    setData(
      rows.map((d) => ({
        ...d,
        profit: d.revenue - d.costs,
      }))
    );
  };

  const exportData = () => {
    const wb = utils.book_new();
    const ws = utils.json_to_sheet(data);
    utils.book_append_sheet(wb, ws, "data");
    writeFileXLSX(wb, "data.xlsx");
  };

  return (
    <div className="App">
      {data.length > 0 && (
        <div className="graph-data">
          <div>
            <ReactDataGrid
              columns={[
                { key: "year", name: "Year" },
                { key: "revenue", name: "Revenue", editor: textEditor },
                { key: "costs", name: "Costs", editor: textEditor },
                { key: "profit", name: "Profit" },
              ]}
              rows={data}
              onRowsChange={updateRows}
            />
          </div>

          <div>
            <LineChart width={600} height={300} data={data}>
              <Tooltip />
              <Line type="monotone" dataKey="revenue" stroke="#8884d8" />
              <Line type="monotone" dataKey="costs" stroke="#fd41f9" />
              <Line type="monotone" dataKey="profit" stroke="#fe1f1a" />
              <XAxis dataKey="year" />
              <YAxis />
            </LineChart>
          </div>
        </div>
      )}

      <button onClick={exportData}>Export [.xlsx]</button>
    </div>
  );
}

export default App;