React Hook の useEffect の async 関数に関する警告: useEffect 関数はクリーンアップ関数を返すか、何も返さない必要があります 質問する

React Hook の useEffect の async 関数に関する警告: useEffect 関数はクリーンアップ関数を返すか、何も返さない必要があります 質問する

useEffect以下のような例を試してみました:

useEffect(async () => {
    try {
        const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
        const json = await response.json();
        setPosts(json.data.children.map(it => it.data));
    } catch (e) {
        console.error(e);
    }
}, []);

コンソールにこの警告が表示されます。ただし、非同期呼び出しの場合、クリーンアップはオプションだと思います。なぜこの警告が表示されるのかわかりません。例についてはサンドボックスをリンクします。https://codesandbox.io/s/24rj871r0p ここに画像の説明を入力してください

ベストアンサー1

Reactバージョン<=17の場合

ぜひご覧になってみてくださいDan Abramov (Reactコアメンテナーの1人)の回答はこちら:

必要以上に複雑にしすぎていると思います。

function Example() {
  const [data, dataSet] = useState<any>(null)

  useEffect(() => {
    async function fetchMyAPI() {
      let response = await fetch('api/data')
      response = await response.json()
      dataSet(response)
    }

    fetchMyAPI()
  }, [])

  return <div>{JSON.stringify(data)}</div>
}

長期的には、競合状態を助長するこのパターンは推奨されません。たとえば、呼び出しの開始と終了の間に何かが起こる可能性があり、新しいプロパティを取得できる可能性があります。代わりに、データ取得にはサスペンスをお勧めします。これは次のようになります。

const response = MyAPIResource.read();

効果はありません。ただし、その間、非同期処理を別の関数に移動して呼び出すことができます。

詳細については、実験的なサスペンス


eslint の外部で関数を使用したい場合。

 function OutsideUsageExample({ userId }) {
  const [data, dataSet] = useState<any>(null)

  const fetchMyAPI = useCallback(async () => {
    let response = await fetch('api/data/' + userId)
    response = await response.json()
    dataSet(response)
  }, [userId]) // if userId changes, useEffect will run again

  useEffect(() => {
    fetchMyAPI()
  }, [fetchMyAPI])

  return (
    <div>
      <div>data: {JSON.stringify(data)}</div>
      <div>
        <button onClick={fetchMyAPI}>manual fetch</button>
      </div>
    </div>
  )
}

Reactバージョン18以上

React 18からはSuspenseも使えるようになりましたが、まだ推奨正しく実装されているフレームワークを使用していない場合:

React 18 では、Relay、Next.js、Hydrogen、Remix などの定評のあるフレームワークでデータ取得に Suspense を使用できるようになりました。Suspense を使用したアドホックなデータ取得は技術的には可能ですが、一般的な戦略としては依然として推奨されません。

フレームワークの一部でない場合は、次のように実装するライブラリを試すことができます。swr


fallbackサスペンスがどのように動作するかを示す単純化された例。サスペンスがそれをキャッチし、最初にコンポーネントを表示し、解決されたMainときにコンポーネントをレンダリングするために、サスペンスにプロミスをスローするpromise必要があります。

let fullfilled = false;
let promise;

const fetchData = () => {
  if (!fullfilled) {
    if (!promise) {
      promise = new Promise(async (resolve) => {
        const res = await fetch('api/data')
        const data = await res.json()

        fullfilled = true
        resolve(data)
      });
    }

    throw promise
  }
};

const Main = () => {
  fetchData();
  return <div>Loaded</div>;
};

const App = () => (
  <Suspense fallback={"Loading..."}>
    <Main />
  </Suspense>
);

おすすめ記事