makes-trail / application-sample

アプリ開発準備
0 stars 0 forks source link

Reactでhello worldする #10

Closed kawabata2018 closed 3 years ago

kawabata2018 commented 3 years ago

背景

To do

完了条件

kawabata2018 commented 3 years ago

useEffectを使った時のcleanupが鬼門。

副作用フックの利用法

useEffectとは?

image

kawabata2018 commented 3 years ago

useEffect cleanup

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

cleanupしてね、と警告が出るコード

useEffect(() => {
  const url = new URL(`${process.env.REACT_APP_SERVERLESS_ENDPOINT}/fetch-isbn-summary`);
  const params = new URLSearchParams();
  params.append("isbn", isbn);
  url.search = params.toString();

  setTimeout(
    async () => {
      const res = await fetch(url.toString());
      if (res.status !== 200) {
        setIsPending(false);
        setIsNoData(true);
        console.log("status code not 200");
        return;
      }
      const data: Array<Book> = await res.json();
      if (data.length === 0) {
        setIsPending(false);
        setIsNoData(true);
        console.log("response data is null");
        return;
      }
      setBook(data[0]);
      setIsPending(false);
      console.log("data fetched successfully!")
    }, 2000
  )
}, [isbn]);

エビデンス

https://user-images.githubusercontent.com/42432622/106385745-3028c080-6415-11eb-97dc-71ff46e3a245.mp4

なぜ警告が出るのか?

マウントされていないコンポーネントの状態(React state)を更新するのは、メモリの無駄遣いだから。

あるコンポーネントで非同期タスクを走らせた後、そのコンポーネントがアンマウントされた(ページを移動するなど)ときに、余計なプロミスについては中断してあげるのが望ましいということ。

cleanup!を使って書いたいい感じのコード

useEffect(() => {
  const url = new URL(`${process.env.REACT_APP_SERVERLESS_ENDPOINT}/fetch-isbn-summary`);
  const params = new URLSearchParams();
  params.append("isbn", isbn);
  url.search = params.toString();

  const abortController = new AbortController();
  setTimeout(
    async () => {
      try {
        const res = await fetch(url.toString(), {
          signal: abortController.signal
        });
        if (res.status !== 200) {
          setIsPending(false);
          setMessage("サーバから正しいステータスが返ってこなかったよ。ぴえん");
          console.log("status code not 200");
          return;
        }
        const data: Array<Book> = await res.json();
        if (data.length === 0) {
          setIsPending(false);
          setMessage("書籍情報がなかったよ。ぴえん");
          console.log("response data is null");
          return;
        }
        setBook(data[0]);
        setIsPending(false);
        console.log("data fetched successfully!")
      }
      catch (err) {
        if (err.name === 'AbortError') {
          console.log("fetch aborted!");
        } else {
          setMessage("予期せぬエラーが出たよ。ぴえん");
          console.error(`Error:\n${err.message}`);
        }
      }
    }, 2000
  )

  // アンマウントされる時にabort!してfetchを強制中止する
  return () => abortController.abort();
}, [isbn]);
kawabata2018 commented 3 years ago

11 がmergeされたので、このissueはclose

追加の調査事項は別途issueを立てる