NITS TIPS

~微塵集合知巧~

初回レンダリング時のみ、useEffect内の処理を実行しないようにする方法

最終更新日: 2024-05-06記事投稿日: 2024-05-06

nobumitsu-1995のgithubトップ

Frontend developer

nobumitsu-1995


概要

 Astroのアイランドアーキテクチャを活用した実装において、SSRとCSRを併用したい場面がありました。

 具体的には、記事検索機能の実装場面で

  • 初期検索結果の取得 → サーバー側でfetchしてSSR
  • 2回目以降の検索結果の取得 → 検索条件の変更をトリガーにClientでfetchしてCSR

という要件を満たしたいということがありました。

 後述のコードのように実装したのですが、これには「初回レンダリング時にせっかくサーバー側でデータを取得しても、client側で再度fetchしてしまいローディングUIが表示されてしまう。」という問題がありました。

const [isLoading, setIsLoading] = useState(false)
const [data, setData] = useState([])

useEffect(() => {
  setIsLoading(true)

  fetchData({
    ...searchParams,
  }).then((res) => { 
    setData(res ?? [])
  }).finally(() => {
    setIsLoading(false)
  })
}, [searchParams])

解決方法とコードの例

 「初回レンダリング時にせっかくサーバー側でデータを取得しても、client側でも再度fetchしてしまいローディングUIが表示されてしまう。」という問題を解決するには、初回のレンダリング時はfetchDataを実行しないようにする必要がありました。

 これは、以下のコードで解決できました。useRefを使用して最初のレンダリングか否かを保持することで、新しいレンダーをトリガしないことを担保しつつ、1回目のレンダリング時のみfetchをしないということを実現しています。

const [isLoading, setIsLoading] = useState(false)
const [data, setData] = useState([])
+ const isFirstRender = useRef(true) // refはコンポーネントに情報を記憶させたいが、新しいレンダーをトリガしたくない場合に有効

useEffect(() => {
+ if (isFirstRender.current) {
+   isFirstRender.current = false // ここでfalseに更新することで2回目以降のレンダリング時は正常にfetchが行われる。
+   return
+ }
  setIsLoading(true)

  fetchData({
    ...searchParams,
  }).then((res) => { 
    setData(res ?? [])
  }).finally(() => {
    setIsLoading(false)
  })
}, [searchParams])

参考文献


関連記事

  • 最終更新日: 2024-04-07記事投稿日: 2024-04-07

    Astroで環境変数を使用する

    Astroで環境変数を使用する方法を紹介します。サーバー側で環境変数を使用する時とクライアント側で環境変数を使用する時とでは少しルールが違います。

  • 最終更新日: 2024-08-06記事投稿日: 2024-08-06

    ARIA属性を活用したアクセシブルなモーダル実装

    アクセシブルなmodalを実装するために必要なaria属性が意外と多い。参考となるコードをメモとして残しておきたい。

  • 最終更新日: 2024-07-27記事投稿日: 2024-07-27

    swiper/reactで実装したカルーセルをTAB操作した時、画面に描画されていないスライドにフォーカスが当たってしまう

    swiper/reactで実装したカルーセルをTABキーで操作した時、画面に描画されていないスライドにもフォーカスが当たってしまう問題があり、それの修正対応をしたので備忘録として残しておく。

  • 最終更新日: 2024-07-09記事投稿日: 2024-07-09

    PayloadとArgumentの使い分け方

    typescriptで型を宣言するとき〇〇Payloadとか××Argumentとか名付けることが多いがその違いについて真面目に考えたことがなかったので調べてみた。