React, TypeScriptでのローディングコンポーネントの作り方
2022-07-17
よちよち歩き

概要

作らなくてもReact SVG Spinnersなどを用いて簡単に実装できます。しかし、ここではSVG SpinnersなどからフリーのSVGを拾ってきて組み込む方法をメモします。

SVGファイルの取得

例えばGitHubなどで次のようなものを見つけた場合は、そのソースコードを取得します。

Display the source blobをクリック
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25"/><path d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

Loading .tsx

以下のコードの<svg>...</svg>の部分に取得したSVGのコードを貼り付けます。そのうえで、// 変更または// 追加のコメントを追加した部分をpropsの値を使うように書き換えています。

import { SVGProps } from 'react';

export function Loading({
  width = 24,
  height = 24,
  color = 'purple',
  dur = '0.75s',
}: SVGProps<SVGElement>):JSX.Element {
  return (
    <svg
      width={width} // 変更
      height={height} // 変更
      fill={color} // 追加
      viewBox='0 0 24 24'
      xmlns='http://www.w3.org/2000/svg'
    >
      <path
        d='M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z'
        opacity='.25'
      />
      <path d='M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z'>
        <animateTransform
          attributeName='transform'
          type='rotate'
          dur={dur} // 変更
          values='0 12 12;360 12 12'
          repeatCount='indefinite'
        />
      </path>
    </svg>
  );
}

使い方

レガシーなReactでの方法ですと次です。

import { useEffect } from 'react';
import { Loading } from './Loading';
:

// 時間のかかる関数
setIsLoading(true);
:
setIsLoading(false);

return (
:
  {isLoading ? <Loading /> : 本来表示するコンポーネント />}
:
);

:

次のように変更すれば、色、サイズ、アニメーションの周期を変更できます。

<Loading />
↓
<Loading color={'yellow'} width={48} height={48} dur={'1.5s'} />