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>
);