skip to Main Content

I know there’s a lot of questions in the same topic. I’ve been reading for about 2 days about this and i cant make it work. So my situation is this:

I have several dynamic routes in my Nextjs app and each fo these routes have a table inside the content. I update the state of that table based on some filters i have setup which is working fine, but when a route changes, the state of the table is still keeping the previous state.
I have tried adding a key to the Table component like this: key={router.asPath} but its not making any difference.

I also added a key to getStaticProps like this:

return {
    props: {
      pageData,
      serverLocations,
      faq,
      key: data?.serverLocations?.data[0]?.attributes.Slug,
    },
    revalidate: 1,
  };

Now i’m trying to update the state on router.events but again, no joy!

Below is my code so you can see what i’m doing wrong:

import { useCallback, useEffect, useState } from "react";
import { Button, useTheme } from "@mui/material";
import PricingTable from "./PricingTable";
import FiltersDialog from "./PricingFilters";
import IconFilters from "./icons/IconFilters";
import Spacer from "./dynamicBlocks/Spacer";
import { useRouter } from "next/router";

export default function TableWithFilters({ theData }: any) {
  const theme = useTheme();
  const router = useRouter();
  const [filtersDialogOpen, setFiltersDialogOpen] = useState(false);

  const Columns = Object.entries(theData[0]).map(([property, columnLabel]) => ({
    property,
    columnLabel,
  }));

  const [state, setState] = useState({
    data: theData,
    filters: Columns.slice(3, -2),
    columns: Columns,
    filterObj: Columns.slice(3, -2).reduce(
      (r: any, { property }: any) => ((r[property] = 0), r),
      {}
    ),
  });
  

  const onFilterApply = ({ target: { value, name } }: any) => {
    const newFilterObj = { ...state.filterObj, [name]: value };
    setState({
      ...state,
      filterObj: newFilterObj,
      data: theData.filter((props: any) =>
        Object.entries(newFilterObj).every(([key, val]: any) => {
          return props[key] >= val;
        })
      ),
    });
  };

  const onRouteChange = useCallback(() => {                              |
    setState({                                                           |
      ...state,                                                          |
      data: theData,                                                     |
      filterObj: Columns.slice(3, -2).reduce(                            |
        (r: any, { property }: any) => ((r[property] = 0), r),           |
        {}                                                               |
      ),                                                                 |
    });                                                                  | This is
  }, [setState]);                                                        | the code
                                                                         |I am trying
  useEffect(() => {                                                      |to use to 
    // subscribe                                                         |fix this
    router.events.on("routeChangeComplete", onRouteChange);              |
    // unsubscribe                                                       |
    return () => router.events.off("routeChangeComplete", onRouteChange);|
  }, [onRouteChange, router.asPath]);                                    |
                                                                         |
  console.log("STATEEE", state);
  console.log("DATAAA", theData);

  return (
    <>
      <FiltersDialog
        openFilters={filtersDialogOpen}
        closeFilters={() => setFiltersDialogOpen(false)}
        staticData={theData}
        filterData={state.filterObj}
        filterProperties={state.filters}
        onFilter={onFilterApply}
      />
      <Button
        onClick={() => setFiltersDialogOpen(!filtersDialogOpen)}
        startIcon={
          <IconFilters
            width='24'
            height='24'
            color={theme.palette.primary.main}
          />
        }
      >
        Open Filters
      </Button>
      <Spacer spacerHeight='40px' />
      <PricingTable
        key={router.asPath}
        tableData={state.data}
        tableColumns={state.columns}
        tableHeader={Columns}
      />
    </>
  );
}

2

Answers


  1. Chosen as BEST ANSWER

    Anyone having similar issue. My mistake was that i shouldn't use useCallback in the onRouteChange function but it should be a plain function like this:

    const onRouteChange = () => {
        setState({
          ...state,
          data: theData,
        });
      };
    

    However @iamippei's solution works as well but i placed the key in the wrong spot. So you can go with whichever solution. Both are working.


  2. You can refer to this. I’m guessing your component position does not change and react preserve its state, actually I can simulate your situation. So could you try following those options? I think option2 is easier to implement. You can check out just to put ‘key’ props with Math.random() whether it works ok or not. If it’s ok, please replace Math.random() with your proper value.(As I mentioned, use Math.random() just to check this solution is ok.)

    parent-component.jsx
    
    export default ParentComponent(){
        return <TableWithFilters key={Math.random()} theData={...}>...</TableWithFilters>
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search