英文:
Nextjs state not updating on route change
问题
I have translated the code part as requested. Here is the translated code:
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),
{}
),
});
}, [setState]);
useEffect(() => {
// subscribe
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}
/>
</>
);
}
I hope this helps. If you have any more questions or need further assistance, feel free to ask.
英文:
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}
/>
</>
);
}
答案1
得分: 2
你可以参考这个链接。我猜测你的组件位置不会改变,React会保持其状态,实际上我可以模拟你的情况。所以你能尝试按照这些选项进行操作吗?我认为选项2更容易实现。你可以尝试只是使用Math.random()
作为 'key' 属性来检查它是否正常工作。如果正常,那么请将 Math.random()
替换为适当的值。(正如我之前提到的,只是使用 Math.random()
来检查这个解决方案是否可行。)
parent-component.jsx
export default function ParentComponent() {
return <TableWithFilters key={Math.random()} theData={...}>...</TableWithFilters>
}
英文:
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>
}
答案2
得分: 0
以下是要翻译的内容:
有人遇到类似的问题吗?我的错误是不应该在onRouteChange
函数中使用useCallback
,而应该是一个普通函数,就像这样:
const onRouteChange = () => {
setState({
...state,
data: theData,
});
};
然而,@iamippei的解决方案也有效,但我把key
放错地方了。所以你可以选择任何一个解决方案。两者都能正常工作。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论