shinke1987.net
雑多な備忘録等のはず。
他のカテゴリ・タブ
目次
PR

React:useSWRの動作確認

2024-05-21 2024-05-21
カテゴリ: React

環境

React:v18.3.1

SWR:v2.2.5

インストール

下記コマンドを実行してインストールする。

% npm install swr

テスト用簡易サーバを用意

HTTPリクエストを受け取ってから2秒後にレスポンスを返す簡易サーバを用意する。

Expressのインストール

% mkdir フォルダ名 && cd フォルダ名
% npm init
% npm install express

// インストールされたExpressのバージョンは4.19.2だった。

% vim app.js

app.jsの内容

const express = require('express')
const app = express()
const port = 3001

function sendResponse(res) {
  res.send('ApiServer : ' + Date());
}

const allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
  res.header(
    'Access-Control-Allow-Headers',
    'Content-Type, Authorization, access_token'
  )

  // intercept OPTIONS method
  if ('OPTIONS' === req.method) {
    res.send(200)
  } else {
    next()
  }
}

app.use(allowCrossDomain)

app.get('/', (req, res) => {
  setTimeout(
    sendResponse,
    2000,
    res 
  );  

  // console.log('req = ', req);
  // console.log('res = ', res);
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

上記app.jsをコピペしたら、下記コマンドを実行してサーバを起動する。

% node app.js

サーバ起動後、Webブラウザで http://localhost:3001 へアクセスし、
「ApiServer : (日時)」と2秒後に表示されれば良い。

App.tsxの内容

import React, {
  createContext, ReactNode, Suspense, useEffect, useLayoutEffect,
} from 'react';
import UseSwr from './UseSwr.tsx';
import Fetch from './Fetch.tsx';

  return (
    <>
      <Fetch />
      <hr />
      <Suspense fallback={<div>Now Loading...</div>}>
        <UseSwr />
      </Suspense>
    </>
  );
}

export default App;

Fetch.tsxの内容

import { ReactNode, useState } from 'react';

function Fetch(): ReactNode {
  const [showFetchData, setShowFetchData] = useState<Promise<string>|string>('初期値');
  const [startFetchData, setStartFetchData] = useState<string>('初期値');
  const [endFetchData, setEndFetchData] = useState<string>('初期値');
  const [countFetchData, setCountFetchData] = useState<number>(0);

  async function fetchData(): Promise<void> {
    setStartFetchData(Date());

    const response: Response = await fetch('http://localhost:3001');
    const promiseText: string = await response.text();
    setShowFetchData(promiseText);

    setEndFetchData(Date());
    setCountFetchData(countFetchData + 1);
  }

  return (
    <>
      <div>
        {`countFetchData = ${countFetchData}`}
        <br />
        {`startFetchData = ${startFetchData}`}
        <br />
        {`showFetchData = ${showFetchData}`}
        <br />
        {`endFetchData = ${endFetchData}`}
      </div>

      <div>
        <button
          type="button"
          onClick={fetchData}
        >
          fetchData
        </button>
      </div>
    </>
  );
}

export default Fetch;

UseSwr.tsxの内容

import { ReactNode, useState } from 'react';
import useSWR, { useSWRConfig } from 'swr';

function UseSwr(): ReactNode {
  // swrData関数用。
  const [startSwrData, setStartSwrData] = useState<string>('初期値');
  const [endSwrData, setEndSwrData] = useState<string>('初期値');
  const [countSwrData, setCountSwrData] = useState<number>(0);
  const [aboutCache, setAboutCache] = useState<ReactNode>(null);

  // キャッシュボタンのイベントハンドラで使用。
  const config = useSWRConfig();

  // useSWRフックで使用されるfetcher。
  async function fetcher(url: string): Promise<string> {
    setStartSwrData(Date());

    const promiseFetch: Response = await fetch(url);

    setEndSwrData(Date());
    setCountSwrData(countSwrData + 1);

    return promiseFetch.text();
  }

  // useSWRフックが成功した後に実行される関数。
  function swrOnSuccess(): void {
    console.log('swrOnSuccess');
    setCountSwrData(countSwrData + 1);
  }

  const { data, mutate } = useSWR<string>(
    'http://localhost:3001',
    fetcher,
    {
      suspense: true, // Suspenseコンポーネント用。20240521_非推奨となっている。
      onSuccess: swrOnSuccess, // 成功した後に実行される関数。
      revalidateIfStale: true, // 古いデータがあっても更新する。
      revalidateOnFocus: false, // フォーカスされても更新しない。
      revalidateOnReconnect: false, // ネットワーク接続復帰時に更新しない。
    },
  );

  const getAboutCache = () => {
    let component: ReactNode = '';

    config.cache.entries().forEach(([key, value]) => {
      component += `<div><div>key = ${key}</div><div>value.data = ${value.data}</div></div><br/>`;
    });
    component += `<div>config.cache.size = ${config.cache.size}</div>`;

    setAboutCache(component);
  };

  const handleRefresh = () => {
    // バウンドミューテートを利用。
    // Suspenseのfallbackは表示されない。
    mutate();
  };

  return (
    <>
      <div>
        {`countSwrData = ${countSwrData}`}
        <br />
        {`startSwrData = ${startSwrData}`}
        <br />
        {`showSwrData = ${data}`}
        <br />
        {`endSwrData = ${endSwrData}`}
      </div>

      <div>
        <button
          type="button"
          onClick={getAboutCache}
        >
          キャッシュ
        </button>
      </div>

      {aboutCache
        && (
          <>
            <br />
            <div dangerouslySetInnerHTML={{ __html: aboutCache }} />
          </>
        )}

      <br />
      <button
        type="button"
        onClick={handleRefresh}
      >
        更新
      </button>
    </>
  );
}

export default UseSwr;

結果

同一カテゴリの記事