Next.js状态在路由更改时未更新

huangapple go评论102阅读模式
英文:

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 &quot;react&quot;;
import { Button, useTheme } from &quot;@mui/material&quot;;
import PricingTable from &quot;./PricingTable&quot;;
import FiltersDialog from &quot;./PricingFilters&quot;;
import IconFilters from &quot;./icons/IconFilters&quot;;
import Spacer from &quot;./dynamicBlocks/Spacer&quot;;
import { useRouter } from &quot;next/router&quot;;
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]) =&gt; ({
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) =&gt; ((r[property] = 0), r),
{}
),
});
const onFilterApply = ({ target: { value, name } }: any) =&gt; {
const newFilterObj = { ...state.filterObj, [name]: value };
setState({
...state,
filterObj: newFilterObj,
data: theData.filter((props: any) =&gt;
Object.entries(newFilterObj).every(([key, val]: any) =&gt; {
return props[key] &gt;= val;
})
),
});
};
const onRouteChange = useCallback(() =&gt; {                              |
setState({                                                           |
...state,                                                          |
data: theData,                                                     |
filterObj: Columns.slice(3, -2).reduce(                            |
(r: any, { property }: any) =&gt; ((r[property] = 0), r),           |
{}                                                               |
),                                                                 |
});                                                                  | This is
}, [setState]);                                                        | the code
|I am trying
useEffect(() =&gt; {                                                      |to use to 
// subscribe                                                         |fix this
router.events.on(&quot;routeChangeComplete&quot;, onRouteChange);              |
// unsubscribe                                                       |
return () =&gt; router.events.off(&quot;routeChangeComplete&quot;, onRouteChange);|
}, [onRouteChange, router.asPath]);                                    |
|
console.log(&quot;STATEEE&quot;, state);
console.log(&quot;DATAAA&quot;, theData);
return (
&lt;&gt;
&lt;FiltersDialog
openFilters={filtersDialogOpen}
closeFilters={() =&gt; setFiltersDialogOpen(false)}
staticData={theData}
filterData={state.filterObj}
filterProperties={state.filters}
onFilter={onFilterApply}
/&gt;
&lt;Button
onClick={() =&gt; setFiltersDialogOpen(!filtersDialogOpen)}
startIcon={
&lt;IconFilters
width=&#39;24&#39;
height=&#39;24&#39;
color={theme.palette.primary.main}
/&gt;
}
&gt;
Open Filters
&lt;/Button&gt;
&lt;Spacer spacerHeight=&#39;40px&#39; /&gt;
&lt;PricingTable
key={router.asPath}
tableData={state.data}
tableColumns={state.columns}
tableHeader={Columns}
/&gt;
&lt;/&gt;
);
}

答案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 &lt;TableWithFilters key={Math.random()} theData={...}&gt;...&lt;/TableWithFilters&gt;
}

答案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 = () =&gt; {
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.

huangapple
  • 本文由 发表于 2023年3月31日 18:57:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897747.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定