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
Anyone having similar issue. My mistake was that i shouldn't use
useCallback
in theonRouteChange
function but it should be a plain function like this: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.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 replaceMath.random()
with your proper value.(As I mentioned, use Math.random() just to check this solution is ok.)