ローディング

1import { faker } from '@faker-js/faker';
2import classNames from 'classnames';
3import { useEffect, useState } from 'react';
4import { HiRefresh } from 'react-icons/hi';
5
6type User = {
7  name: string;
8  gender: string;
9  imageURL: string;
10};
11
12const Loading = () => {
13  const [user, setUser] = useState<User>();
14
15  useEffect(() => {
16    fetchUser();
17  }, []);
18
19  const fetchUser = () => {
20    setTimeout(() => {
21      setUser({
22        name: faker.name.findName(),
23        gender: faker.name.gender(),
24        imageURL: faker.image.avatar(),
25      });
26    }, 5000);
27  };
28
29  return (
30    <div>
31      <button
32        className="text-gray-600"
33        onClick={() => {
34          setUser(undefined);
35          fetchUser();
36        }}
37      >
38        読み込み
39      </button>
40
41      <div
42        className={classNames(
43          'flex gap-6 mt-6 rounded-md bg-gray-700 shadow w-96 max-w-full p-6',
44          !user && 'animate-pulse'
45        )}
46      >
47        <div className="w-10 h-10 bg-gray-400 rounded-full overflow-hidden">
48          {user?.imageURL && <img src={user.imageURL} alt="" />}
49        </div>
50        <div>
51          {user ? <p>{user.name}</p> : <Placeholder className="w-44" />}
52          <div className="mt-1">
53            {user ? (
54              <p className="text-gray-500">{user.gender}</p>
55            ) : (
56              <Placeholder />
57            )}
58          </div>
59        </div>
60      </div>
61
62      <div className="mt-10">
63        {!user && <HiRefresh className="animate-spin text-4xl text-gray-700" />}
64      </div>
65    </div>
66  );
67};
68
69export default Loading;
70
71const Placeholder = ({ className }: { className?: string }) => {
72  return (
73    <div className="h-6 flex items-center">
74      <p
75        className={classNames(
76          `h-3 rounded-full bg-gray-500`,
77          className || 'w-20'
78        )}
79      ></p>
80    </div>
81  );
82};

使用ライブラリ

なし

参考サイト