Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error for useStore: Warning: The result of getSnapshot should be cached to avoid an infinite loop #22

Closed
adamtaylor13 opened this issue Sep 13, 2023 · 14 comments · Fixed by #30

Comments

@adamtaylor13
Copy link

adamtaylor13 commented Sep 13, 2023

I'm using nanostores (0.9.3), in astro (1.9.0) with react (18.0.0).

I've got this store:

import { DataResponse } from "@components/hooks/useApi";
import { createFetcherStore } from "@stores/apiFetcher";
import { useStore } from "@nanostores/react";

export const $account = createFetcherStore<DataResponse<"/account">>([
    "/account",
]);

export const useAccount = () => {
    const fetchResults = useStore($account);
    
    // ...

    return fetchResults;
};

Used in a React component like so:

export default function NavAuthOptions() {
    const { data: account } = useAccount();
    // ...
}

And I get this error in the console:
CleanShot 2023-09-13 at 09 51 56@2x

I should note however that there doesn't actually appear to be any errors. The site seems to function just fine, which may actually be more disconcerting than the error itself!

My Google-Fu has failed me here as the only semi-related issue I could find was this pmndrs/zustand#1936, however it doesn't appear related as I don't have a .getState() function.

I've also tried just using useStore($account) directly inside my component instead of importing useAccount, but the error still shows in the console.

@grctest
Copy link

grctest commented Oct 22, 2023

Also getting this error using nanostore query/react with react + astro

Any luck resolving it?

My code for reference: https://github.com/BTS-CM/astro-ui/blob/main/src/components/common/DeepLinkDialog.jsx

@adamtaylor13
Copy link
Author

@grctest Unfortunately no—we've just shipped it with the error, which hasn't seemed to affect our site at all. But like I said above, that's more disconcerting than the error itself. Why would we be logging errors if there isn't actually an error? So far no one from nanostores has reached out to assist with this :/

@grctest
Copy link

grctest commented Oct 22, 2023

It seems like it's a known React issue? facebook/react#24508 (comment)

@constantineMelios85
Copy link

Is there any updates on this issue. I have the same with nanostores/query and nanostores/react.

@ai
Copy link
Member

ai commented May 28, 2024

I am not using React anymore, so someone else needs to do research and find a solution.

@JosefJezek
Copy link

JosefJezek commented Aug 15, 2024

I found this solution...
image

const $polls = createFetcherStore<Polls>(["/demo/polls.json"]);
const data = useStore($polls, {}, "data");
console.log(data);

but useStore() does call render second time :-/ maybe React feature
image

opts.keys param causes much more changes... listenKeys() has some bug... data key is key of createFetcherStore

let store = useStore($polls, {keys: ["data"]});
console.log(store);

image

@JosefJezek
Copy link

@ai could you fix this issue?

@ai
Copy link
Member

ai commented Aug 16, 2024

@JosefJezek can use send PR? I can’t copy code from screenshots.

@JosefJezek
Copy link

my change in useStore...

const getKey = () => {
  const store = get();
  return storeKey ? store[storeKey] : store;
};

return useSyncExternalStore(subscribe, getKey, getKey);

@ai
Copy link
Member

ai commented Aug 16, 2024

@JosefJezek we don’t have storeKey in the useStore. Please, send PR, it will be faster.

@JosefJezek
Copy link

my solution is not perfect... we need const { data, loading, error } = useStore($post);, not only one key data

please fix createFetcherStore, this store has too many changes

@yuyi919
Copy link
Contributor

yuyi919 commented Sep 22, 2024

I've encountered an same issue where listenKeys in createFetcherStore causes excessive responses (or updates). To address this, I implemented the following temporary solution, which works for my use case:

export function useStoreFixed<SomeStore extends Store>(
  store: SomeStore,
  { keys, deps = [store, keys] }: UseStoreOptions<SomeStore> = {},
): StoreValue<SomeStore> {
  let snapshotRef = useRef() as React.MutableRefObject<StoreValue<SomeStore>>;
  snapshotRef.current = store.get();

  let get = () => snapshotRef.current;

  return useSyncExternalStore(
    useCallback(
      (onChange) =>
        keys?.length! > 0
          ? listenKeys(store as any, keys!, emit(snapshotRef, onChange))
          : store.listen(emit(snapshotRef, onChange)),
      deps,
    ),
    get,
    get,
  );
}
const emit =
  <T>(snapshot: React.MutableRefObject<T>, onChange: () => void) =>
  (value: T) => {
    snapshot.current = value;
    onChange();
  };

Ideally, this issue should be resolved on the library's end to prevent unnecessary reactivity.

@ai
Copy link
Member

ai commented Sep 22, 2024

@yuyi919 can you send PR of your fix to the repo?

@ai
Copy link
Member

ai commented Sep 23, 2024

The fix by @yuyi919 was released in 0.8.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants