Search code examples
javascriptreactjsmaterial-tablereact-chartjs

React re-render Material table after filter event


In my application with React, I have created a dashboard in which I show the data in graphs and with a summary table. I have two graphs, one donut and one histogram and they are both filterable. In particular, when I filter on the donut chart I need to update the data in the table as well. To avoid a second API call, to filter the data on the table I used the JS filter() function but when I filter on the chart, the table is not updated (re-rendered) with the filtered data.

Do you have any suggestions or advice? Is there a better way to do this?

my code:

  • DashboardContent.js
import React, { useEffect, useState } from "react";
import Grid from "@material-ui/core/Grid";
import DashCard from "./DashboardCard" // eliminabile
import HomeDoughChart from '../charts_js/HomeDoughChart'
import tableIcons from '../templates/TableIcons';
import HomeBarChart from "../charts_js/HomeBarChart";
import MaterialTable from "material-table";
import {
   getDashboard_Data,
   getDashboard_Data_byYear,
   getDashboard_TributeFiler,
   getDashboard_YearFiler,
   getDashboard_Data_byYear_andTribute,
   getDashboard_Contribuenti_byYear_andTribute,
   getTableData
} from "../../repo/dashboardRepo";
import { Card, CardContent, CardHeader } from "@material-ui/core";
import { SettingsBackupRestoreOutlined } from "@material-ui/icons";

const DashboardContent = () => {
   const [chart, setChart] = useState([])
   const [barchart, setBarChart] = useState([])
   const [barchart1, setBarChart1] = useState([])
   const [barchart2, setBarChart2] = useState([])
   const [barchart3, setBarChart3] = useState([])
   const [trib, setTributi] = useState([])
   const [year, setAnni] = useState([])
   const [dashboardfilter, setDashboardFilter] = useState({ year: "", tributo: "" });
   const [barTribute, setBarTribute] = useState([]);

   function handleYearChange(evt) {
      setDashboardFilter({ year: evt.target.value, tributo: dashboardfilter.tributo });
      const yf = async () => {
         const res = (dashboardfilter.year !== "") ? await getDashboard_Data_byYear_andTribute(dashboardfilter.year, dashboardfilter.tributo) : await getDashboard_Data();
         //const res1 = (dashboardfilter.year !== "") ? await getDashboard_Contribuenti_byYear_andTribute(dashboardfilter.year, dashboardfilter.tributo) : await getDashboard_Contribuenti_byYear_andTribute();
         setChart(res.data.data);
      }
      yf();
   }

   function handleTributeChange(evt) {
      setDashboardFilter({ year: dashboardfilter.year, tributo: evt.target.value });
      const yf = async () => {
         const res = (dashboardfilter.tributo !== "") ? await getDashboard_Data_byYear_andTribute(dashboardfilter.year, dashboardfilter.tributo) : await getDashboard_Data();
         //const res1 = (dashboardfilter.year !== "") ? await getDashboard_Contribuenti_byYear_andTribute(dashboardfilter.year, dashboardfilter.tributo) : await getDashboard_Contribuenti_byYear_andTribute();
         setChart(res.data.data);
      }
      yf();
   }

   function handleBarTributeChange(evt) {

      setBarTribute({ b_trib: evt.target.value });
      const tf = async () => {
         const res1 = (barTribute.b_trib === "Tutti") ? await getDashboard_Data_byYear(2022) : await getDashboard_Data_byYear_andTribute(2022, barTribute.b_trib);
         const res2 = (barTribute.b_trib === "Tutti") ? await getDashboard_Data_byYear(2021) : await getDashboard_Data_byYear_andTribute(2021, barTribute.b_trib);
         const res3 = (barTribute.b_trib === "Tutti") ? await getDashboard_Data_byYear(2020) : await getDashboard_Data_byYear_andTribute(2020, barTribute.b_trib);
         const res4 = (barTribute.b_trib === "Tutti") ? await getDashboard_Data_byYear(2019) : await getDashboard_Data_byYear_andTribute(2019, barTribute.b_trib);
         setBarChart(res1.data.data);
         setBarChart1(res2.data.data);
         setBarChart2(res3.data.data);
         setBarChart3(res4.data.data);
      }
      tf();
   }

   useEffect(() => {
      const a = async () => {
         if (dashboardfilter.year === "" && dashboardfilter.tributo === "") {
            const res = await getDashboard_Data();
            //const res1 = await getDashboard_Contribuenti_byYear_andTribute();
            setChart(res.data.data);
         }
      }
      a()
   }, [])

   useEffect(() => {
      var today = new Date();
      const year = today.getFullYear()
      const b = async () => {
         const res1 = await getDashboard_Data_byYear(year);
         const res2 = await getDashboard_Data_byYear(year-1);
         const res3 = await getDashboard_Data_byYear(year-2);
         const res4 = await getDashboard_Data_byYear(year-3);
         setBarChart(res1.data.data);
         setBarChart1(res2.data.data);
         setBarChart2(res3.data.data);
         setBarChart3(res4.data.data);
      }
      b()
   }, [])

   useEffect(() => {
      const c = async () => {
         const res2 = await getDashboard_TributeFiler();
         const res3 = await getDashboard_YearFiler();
         setTributi(res2.data.data);
         setAnni(res3.data.data);
      }
      c();
   }, [])

   return (
      <div>
         <div style={{ display: "flex", flex: "1", flexDirection: "row", alignItems: "stretch", justifyContent: 'space-evenly' }}>
            <Card style={{ marginLeft: 30, responsive: true, marginTop: 30, marginRight: 30, flex: 0.85 }}>
               <CardHeader title={"Consuntivo totale dei pagamenti"} style={{ textAlign: "left" }} />
               <CardContent>
                  <Grid container direction="row" style={{ marginTop: '10px', marginLeft: '20px', marginBottom: '60px' }} >
                     <div>
                        <form justifyContent="left">
                           <label>Filtra per anno di riferimento </label>
                           <select name="year" value={dashboardfilter.year} onChange={handleYearChange}>
                              <option value="">Tutti gli anni</option>
                              {year.map(y => {
                                 return (
                                    <option key={y.anno} value={y.anno}>
                                       {y.anno}
                                    </option>
                                 )
                              })}
                           </select>
                           <br />
                           <label>Filtra per tributo </label>
                           <select name="tributo" value={dashboardfilter.tributo} onChange={handleTributeChange}>
                              <option value="">Tutti i tributi</option>
                              {trib.map(tributi => {
                                 return (
                                    <option key={tributi.descrizioneServizio} value={tributi.descrizioneServizio}>
                                       {tributi.descrizioneServizio}
                                    </option>
                                 )
                              })}
                           </select>
                        </form>
                        <br />
                        <h3>Totale da riscuotere: {Intl.NumberFormat('it-IT', { style: 'currency', currency: 'EUR' }).format(chart.totaleDaPagare)} </h3>
                        <HomeDoughChart chart={chart} />
                     </div>
                  </Grid>
               </CardContent>
            </Card>
            <Card style={{ marginLeft: 30, responsive: true, marginTop: 30, marginRight: 30, flex: 1 }}>
               <CardHeader title={"Consuntivo dei pagamenti per anno"} style={{ textAlign: "left" }} />
               <CardContent >
                  {/* qui dobbiamo inserire i filtri, il titolo del grafico e il valore del filtro per tributo del grafico a istogramma */}
                  <Grid container direction="row" justify="left" alignItems="center" style={{ marginTop: '10px', marginLeft: '20px', marginBottom: '60px' }}>
                     <div>
                        <form>
                           <label>Filtra per tributo </label>
                           <select name="tributoBar" value={barTribute.b_trib} onChange={handleBarTributeChange}>
                              <option value="Tutti">Tutti i tributi</option>
                              {trib.map(tributi => {
                                 return (
                                    <option key={tributi.descrizioneServizio} value={tributi.descrizioneServizio}>
                                       {tributi.descrizioneServizio}
                                    </option>
                                 )
                              })}
                           </select>
                        </form>
                        <br />
                        <h3>Tributo di riferimento: {barTribute.b_trib}</h3>
                     </div>
                     <HomeBarChart barchart={barchart} barchart1={barchart1} barchart2={barchart2} barchart3={barchart3} />
                  </Grid>
               </CardContent>
            </Card>
         </div>
         <div style={{ display: "flex", flex: "1", flexDirection: "row", alignItems: "center", responsive: true }}>
            <Grid container spacing={1} style={{ marginLeft: 30, marginTop: 30, marginRight: 30, flex: 1 }}>
               <MaterialTable
                  title="Consuntivo posizioni"
                  options={{
                     sorting: true,
                     actionsColumnIndex: -1,
                     pageSize: 5,
                     toolbar: true,
                     paging: false,
                     responsive: true,
                     exportButton: true,
                     exportAllData: true,
                     exportFileName: "ConsuntivoPosizioni",
                     filtering: false,
                     grouping: true,
                  }}
                  icons={tableIcons}
                  columns={[
                     { title: 'Tributo', field: 'tributo' },
                     { title: 'Anno Riferimento', field: 'docAnnoRif', defaultGroupSort: "desc"},
                     { title: '#Contribuenti', field: 'totcontribuenti' },
                     { title: '#Documenti', field: 'atti', type: 'numeric' },
                     { title: 'Importo pagamento', field: 'totaleDovuto',type: "currency", currencySetting:{ currencyCode:'EUR', minimumFractionDigits:2, maximumFractionDigits:2} },
                     { title: 'Importo pagato', field: 'totaleVersato',type: "currency", currencySetting:{ currencyCode:'EUR', minimumFractionDigits:2, maximumFractionDigits:2} },
                     { title: 'Importo restante', field: 'restante', type: "currency", render: rowData => (Intl.NumberFormat('it-IT', { style: 'currency', currency: 'EUR' }).format(rowData.totaleDovuto-rowData.totaleVersato)) },
                  ]}
                  data={async () => {
                     const res = await getTableData();
                     return({
                        data: (dashboardfilter.year === "") ? res.data.data : res.data.data.filter(element => element.docAnnoRif = dashboardfilter.year ) ,
                     })
                  }}
               />
            </Grid>
         </div>
      </div>
   )
}
export default DashboardContent;


Solution

  • You likely need to store your data in the component state:

        const [graphData, setGraphData] = useState([]);
        useEffect(() => {
            getTableData().then(setGraphData);
        }, []);
    
     <MaterialTable
       title="Consuntivo posizioni"
       ...
       data={graphData}
     />
    

    Then you can change the data at any time using the setGraphData method.