【问题标题】:Recoil updating state when nothing has changed什么都没有改变时反冲更新状态
【发布时间】:2022-12-22 07:59:52
【问题描述】:

因此,我最近开始使用 useRecoilStateLoadable 通过反冲来使用我的 API 端点,它工作得很好,但我遇到的一个问题是在我的数据表上,我希望它在用户选择例如第 2 页或搜索某些内容时执行另一个 API 调用,目前这是我的原子和选择器的样子:

const entriesPerPage : EntriesPerPage = {defaultValue: 10};

export const filterScorecard = atom<ScorecardSearchRequest>({
    key: 'filterScorecard',
    default: {
        Draw: 2,
        PageNumber: 1,
        PageSize: entriesPerPage.defaultValue!,
        SortColumnNames: [],
        SortDirections: [],
        SearchValue: '',
        ConsolidationValues: null,
        IsGroupDataManagement: false,
        OnlySearchLockedScorecards: null,
        ScorecardEndDate: null,
        ScorecardTypes: ["43"],
        Usernames: null,
    }
})

export const allScorecardSelector = selector<ScorecardLicense>({
    key: 'allScorecardSelector',
    get: async ({get}) => {
        
        const filterScorecardData = get(filterScorecard);
        console.log(filterScorecard)
        try{
            const scorecardSearchResult = await BEEScorecardService.getUserScorecards(filterScorecardData);
            return scorecardSearchResult.data;
        }catch (error){
            console.error(error);
            return defaultObject;
        }
    }
})

export const allScorecardAtom = atom<ScorecardLicense>({
    key: 'allScorecardAtom',
    default: allScorecardSelector
})

我创建了 filterScorecard 方法来在状态更改时重新触发我的 API,在我的组件中,在 useEffect 中我的代码如下所示:

    const [entriesPerPage, setEntriesPerPage] = useState<EntriesPerPage>({ defaultValue: 10 });

    const [pageNumber, setPageNumber] = useState<number>(1);
    const [searchValue, setSearchValue] = useState<string>('');
    const [sortColumnNames, setSortColumnNames] = useState<string[]>([]);
    const [sortDirections, setSortDirections] = useState<SortDirections[]>([]);
    useEffect(() => {
            setFilterScorecard(prevState => ({
                ...prevState,
                pageNumber,
                entriesPerPage,
                searchValue,
                sortColumnNames,
                sortDirections
            }))
        }, [entriesPerPage, pageNumber, searchValue, sortColumnNames, sortDirections]);

但我注意到的是,每次我离开并返回时,API 都会在不应该被触发时被触发,如果我删除使用效果并导航离开并返回,则 API 不会加载并且它显示正确数据,但我无法搜索或转到下一页,因为当然不再调用 filterScorecard 方法。我想弄清楚我需要做什么,以便在状态没有任何变化的情况下不执行 API 调用。

更新

我已经创建了一个代码沙盒来向您展示问题,如果您单击“about”,它会触发 API,但如果您单击“home”,然后再次单击“about”,它仍然会触发 API 请求,这不应该是因为状态没有任何变化。仅当我单击下一页时,它才真正再次调用 API

Code Sandbox

【问题讨论】:

  • 我没有理解你所说的“什么都没有改变时更新状态”的意思。第二个 sn-p 中的 useEffect hook 有什么特别之处?什么是setFilterScorecard?它看起来就像一个 useState updater 函数的名字。 useEffect 钩子是否被调用更多的比你想象的要多?您指的是什么 API 调用?您能否编辑帖子以包含您正在使用的所有相关代码并在使用时遇到问题?见minimal reproducible example
  • 你是什​​么意思“每次你离开并回来”?你能给个例子吗?
  • @DrewReese 我已经在代码沙箱中添加了我遇到的问题
  • @g0rb 我添加了一个问题的代码沙箱
  • 从我看到的useRecoilStateLoadable 的代码和文档来看,代码似乎符合我的预期。导航到 "/about"About 组件安装并运行效果。向后导航,About卸载,再次导航至"/about" and About` 挂载并运行效果。单击下一步按钮时我看到相同的行为,效果运行。不可否认,虽然我不熟悉后坐力。你是说应该缓存一些东西,比如 getAllSelector fetch 的 GET 请求响应值?

标签: reactjs react-hooks recoiljs


【解决方案1】:

每次导航到组件时都会发送 API 请求的原因是异步选择器依赖项在每次安装组件时都会发生变化。

如果任何依赖项发生变化,选择器将被重新评估并执行新的查询。

https://recoiljs.org/docs/guides/asynchronous-data-queries#asynchronous-example

什么是选择器的依赖?

const selector = selector({
  key: "getAllSelector",
  get: async ({ get }) => {
    const filterScorecardData = get(filterScorecard);  <-- this is a dependency

    const res = await fetch(`https://my-api`);
  }
});

每次安装组件时,都会更新 filterScorecard 状态。

...
useEffect(() => {
  setFilterScorecard(prevState => ({
    ...prevState,
    pageNumber,
    etc.,
  }));

因为您正在更新每个组件安装的依赖状态, allScorecardSelector 选择器将在每个组件安装时重新评估和执行。

为了防止 API 请求在组件挂载时触发,您需要避免在每个组件挂载时更新 filterScorecard 状态。

【讨论】:

  • 你知道我怎样才能做到这一点而不触发每个组件安装吗?
  • 您应该尝试将 setFilterScorecarduseEffect 移动到 UI 处理程序回调,即 onClick 回调。我很难准确地告诉您您最了解您的应用程序应该如何运行。
猜你喜欢
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 2021-08-04
  • 2020-08-21
  • 1970-01-01
  • 2020-07-22
  • 2020-10-09
相关资源
最近更新 更多