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};
なし