subaru-hello / TracksForPrivateAthleteDB

今日個人向けに開放されている競技場を検索できるサービスです
https://hurdle.biz
0 stars 0 forks source link

useEffect内のdatafetchingに順序をつける #36

Open subaru-hello opened 1 year ago

subaru-hello commented 1 year ago

useEffectが返却する型は、副作用を完全に無くすために、undefined又はfunctionでないといけない。 そのため、下記のように、useEffectに対してasyncを付けるとPromiseを返してしまうためNG。 Not


useEffect(async () => {
  const data = await fetchData();
}, [fetchData])

Promise文は関数宣言文を用意してから実行する必要がある。 But

useEffect(() => {
  // declare the data fetching function
  const fetchData = async () => {
    const data = await fetch('https://yourapi.com');
  }

  // call the function
  fetchData()
    // make sure to catch any error
    .catch(console.error);
}, [])

参考

https://devtrium.com/posts/async-functions-useeffect

subaru-hello commented 1 year ago

async/awaitを用いてdata fetchして返ってきたresponceをアプリ内のstateに入れたい時は、data fetchするサイクル内に入れる必要がある。 さもないと、期待する挙動ではなく、Promiseがstateに入ってしまう。 Not


useEffect(() => {
  // declare the async data fetching function
  const fetchData = async () => {
    // get the data from the api
    const data = await fetch('https://yourapi.com');
    // convert data to json
    const json = await data.json();
    return json;
  }

  // call the function
  const result = fetchData()
    // make sure to catch any error
    .catch(console.error);;

  // ❌ don't do this, it won't work as you expect!
  setData(result);
}, [])

But


useEffect(() => {
  // declare the async data fetching function
  const fetchData = async () => {
    // get the data from the api
    const data = await fetch('https://yourapi.com');
    // convert the data to json
    const json = await response.json();

    // set state with the result
    setData(json);
  }

  // call the function
  fetchData()
    // make sure to catch any error
    .catch(console.error);;
}, [])
subaru-hello commented 1 year ago

data fetchingをする関数をuseEffectの外側で定義したい場合は、useCallbackを使う必要がある。 そうしないと、UIがレンダーされる度にdata fetchingをする関数が実行されてしまう。 同時に、useEffectは依存配列内でdata fetchingをする関数をバインドしているため、UIがレンダーされる度にuseEffectも実行されてしまう。

// declare the async data fetching function
const fetchData = useCallback(async () => {
  const data = await fetch('https://yourapi.com');

  setData(data);
}, [])

// the useEffect is only there to call `fetchData` at the right time
useEffect(() => {
  fetchData()
    // make sure to catch any error
    .catch(console.error);;
}, [fetchData])

https://devtrium.com/posts/dependency-arrays

subaru-hello commented 1 year ago

パラメーターが渡ってきた場合の挙動。 ユーザー詳細画面にuserID1が渡ってきた際に、data fetchingが2回走らないようにしたい。 結構簡単で、条件分岐を足してあげれば良い。 最初はtrueにしてある変数を、useEffectの終わりにfalseに変えるような記述にしておくと、paramに変更がない限り、Dataは2回セットされる事が無くなる。 便利

useEffect(() => {
  let isSubscribed = true;

  // declare the async data fetching function
  const fetchData = async () => {
    // get the data from the api
    const data = await fetch(`https://yourapi.com?param=${param}`);
    // convert the data to json
    const json = await response.json();

    // set state with the result if `isSubscribed` is true
    if (isSubscribed) {
      setData(json);
    }
  }

  // call the function
  fetchData()
    // make sure to catch any error
    .catch(console.error);;

  // cancel any future `setData`
  return () => isSubscribed = false;
}, [param])

https://devtrium.com/posts/async-functions-useeffect#note-on-fetching-data-inside-useeffect