最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why is useFetcher causing an re-render infinite loop? - Stack Overflow

programmeradmin1浏览0评论

I have an input. On every change to the input, I want to call an API.

Here's a simplified version of the code:

  // updated by input
  const [urlText, setUrlText] = useState("");

  const fetcher = useFetcher();

  useEffect(() => {
    if (urlText === "" || !fetcher) return;
    fetcher.load(`/api/preview?url=${urlText}`);
  }, [urlText]);

The issue is, when I put urlText inside of the dependencies array, there is an infinite rendering loop, and React claims the issue is I might be updating state inside of the useEffect. However, as far as I can tell, I'm not updating any state inside of the hook, so I'm not sure why an infinite re-render is happening.

Any thoughts?

The fuller version of the code is:

Note: The bug still happens without the debounce, or the useMemo, all of that stuff is roughly irrelevant.

export default function () {
  const { code, higlightedCode } = useLoaderData<API>();

  const [urlText, setUrlText] = useState("");
  const url = useMemo(() => getURL(prefixWithHttps(urlText)), [urlText]);
  const debouncedUrl = useDebounce(url, 250);

  const fetcher = useFetcher();

  useEffect(() => {
    if (url === null || !fetcher) return;
    fetcher.load(`/api/preview?url=${encodeURIComponent(url.toString())}`);
  }, [debouncedUrl]);

  return (
             <input
            type="text"
            placeholder="Paste URL"
            className={clsx(
              "w-full rounded-sm bg-gray-800 text-white text-center placeholder:text-white"
              //"placeholder:text-left text-left"
            )}
            value={urlText}
            onChange={(e) => setUrlText(e.target.value)}
          ></input>
  );
}

I have an input. On every change to the input, I want to call an API.

Here's a simplified version of the code:

  // updated by input
  const [urlText, setUrlText] = useState("");

  const fetcher = useFetcher();

  useEffect(() => {
    if (urlText === "" || !fetcher) return;
    fetcher.load(`/api/preview?url=${urlText}`);
  }, [urlText]);

The issue is, when I put urlText inside of the dependencies array, there is an infinite rendering loop, and React claims the issue is I might be updating state inside of the useEffect. However, as far as I can tell, I'm not updating any state inside of the hook, so I'm not sure why an infinite re-render is happening.

Any thoughts?

The fuller version of the code is:

Note: The bug still happens without the debounce, or the useMemo, all of that stuff is roughly irrelevant.

export default function () {
  const { code, higlightedCode } = useLoaderData<API>();

  const [urlText, setUrlText] = useState("");
  const url = useMemo(() => getURL(prefixWithHttps(urlText)), [urlText]);
  const debouncedUrl = useDebounce(url, 250);

  const fetcher = useFetcher();

  useEffect(() => {
    if (url === null || !fetcher) return;
    fetcher.load(`/api/preview?url=${encodeURIComponent(url.toString())}`);
  }, [debouncedUrl]);

  return (
             <input
            type="text"
            placeholder="Paste URL"
            className={clsx(
              "w-full rounded-sm bg-gray-800 text-white text-center placeholder:text-white"
              //"placeholder:text-left text-left"
            )}
            value={urlText}
            onChange={(e) => setUrlText(e.target.value)}
          ></input>
  );
}
Share Improve this question edited Jun 6, 2022 at 7:42 Foobar asked Jun 6, 2022 at 7:16 FoobarFoobar 8,54521 gold badges101 silver badges183 bronze badges 2
  • Could you please provide the full version of this ponent? You might update your state somewhere else. – Ryan Le Commented Jun 6, 2022 at 7:20
  • 1 @RyanLe done, i'll make a stackblitz too – Foobar Commented Jun 6, 2022 at 7:29
Add a ment  | 

3 Answers 3

Reset to default 5

The problem you're having is that fetcher is updated throughout the fetch process. This is causing your effect to re-run, and since you are calling load again, it is repeating the cycle.

You should be checking fetcher.state to see when to fetch.

useEffect(() => {
  // check to see if you haven't fetched yet
  // and we haven't received the data
  if (fetcher.state === 'idle' && !fetcher.data) {
    fetcher.load(url)
  }
}, [url, fetcher.state, fetcher.data])

https://remix.run/docs/en/v1/api/remix#usefetcher

You might by setting state in useFetcher hook, please check code of load method from useFetcher.

Update: I'm silly. useDebounce returns an array.

发布评论

评论列表(0)

  1. 暂无评论