Skip to content

Commit 60c2a6a

Browse files
useExhibitions をリトライできるようにする (#225)
* fix(client/pages/Index.tsx): add refetch button to handle error and re-fetch data fix(client/pages/scss/index.module.scss): add styles for error section * fix(component): change the fallback component to use a div instead of a section to improve semantic correctness * fix(api.ts): change error messages to japanese to improve localization * fix(client/hooks/exhibition.ts): add dependency to fetchExhibitions to the useEffect hook
1 parent af18784 commit 60c2a6a

File tree

5 files changed

+45
-25
lines changed

5 files changed

+45
-25
lines changed

client/src/api/exhibition.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export async function getExhibitions(): Promise<
66
> {
77
const response = await fetch(endpoint("/exhibitions"));
88
if (!response.ok) {
9-
throw new Error("Failed to fetch exhibitions");
9+
throw new Error("華展一覧の取得に失敗しました。");
1010
}
1111
return response.json();
1212
}
@@ -22,7 +22,7 @@ export async function getExhibition(
2222
);
2323
const response = await fetch(path);
2424
if (!response.ok) {
25-
throw new Error(`Failed to fetch exhibition with ID ${exhibitionId}`);
25+
throw new Error(`華展ID ${exhibitionId} の華展情報取得に失敗しました。`);
2626
}
2727
return response.json();
2828
}
@@ -38,7 +38,7 @@ export async function getExhibitionWorkListItems(
3838
);
3939
const response = await fetch(path);
4040
if (!response.ok) {
41-
throw new Error(`Failed to fetch works for exhibition with ID ${exhibitionId}`);
41+
throw new Error(`華展ID ${exhibitionId} の作品一覧取得に失敗しました。`);
4242
}
4343
return response.json();
4444
}
@@ -54,7 +54,7 @@ export async function getExhibitionWorkListItem(
5454
.replace("{workId}", String(workId));
5555
const response = await fetch(path);
5656
if (!response.ok) {
57-
throw new Error(`Failed to fetch work with ID ${workId} for exhibition ${exhibitionId}`);
57+
throw new Error(`華展ID ${exhibitionId} の作品ID ${workId} の取得に失敗しました。`);
5858
}
5959
return response.json();
6060
}

client/src/components/Fallback.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import styles from "./scss/fallback.module.scss";
22

33
export default function Fallback({ message, isError }: { message: string; isError?: boolean }) {
44
return (
5-
<section className={styles.fallback} role="status">
5+
<div className={styles.fallback} role="status">
66
<p className={isError ? styles.error : styles.normal}>{message}</p>
7-
</section>
7+
</div>
88
);
99
}

client/src/hooks/exhibition.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,39 @@ interface UseExhibitionsReturn {
1414
exhibitions: Record<number, Exhibition>;
1515
isLoading: boolean;
1616
errorMessage: string | null;
17+
refetch: () => void; // この API が特にデータ取得に失敗する確率が高いので、再取得のための refetch 関数を追加
1718
}
1819

1920
export function useExhibitions(): UseExhibitionsReturn {
2021
const [exhibitions, setExhibitions] = useState<Record<number, Exhibition>>({});
2122
const [isLoading, setIsLoading] = useState<boolean>(true);
2223
const [errorMessage, setErrorMessage] = useState<string | null>(null);
23-
useEffect(() => {
24-
async function fetchExhibitions() {
25-
try {
26-
setIsLoading(true);
27-
setErrorMessage(null);
28-
const fetchedExhibitions = await getExhibitions();
29-
setExhibitions(fetchedExhibitions);
30-
} catch (error) {
31-
const message = error instanceof Error ? error.message : "Unknown error occurred";
32-
console.error("Failed to fetch exhibitions:", error);
33-
setErrorMessage(message);
34-
setExhibitions({}); // エラー時は空のオブジェクトを設定
35-
} finally {
36-
setIsLoading(false);
37-
}
24+
25+
const fetchExhibitions = async () => {
26+
try {
27+
setIsLoading(true);
28+
setErrorMessage(null);
29+
const fetchedExhibitions = await getExhibitions();
30+
setExhibitions(fetchedExhibitions);
31+
} catch (error) {
32+
const message = error instanceof Error ? error.message : "Unknown error occurred";
33+
console.error("Failed to fetch exhibitions:", error);
34+
setErrorMessage(message);
35+
setExhibitions({}); // エラー時は空のオブジェクトを設定
36+
} finally {
37+
setIsLoading(false);
3838
}
39+
};
40+
41+
const refetch = () => {
3942
fetchExhibitions();
40-
}, []);
41-
return { exhibitions, isLoading, errorMessage };
43+
};
44+
45+
useEffect(() => {
46+
fetchExhibitions();
47+
}, [fetchExhibitions]);
48+
49+
return { exhibitions, isLoading, errorMessage, refetch };
4250
}
4351

4452
interface UseExhibitionReturn {

client/src/pages/Index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,19 @@ function ExhibitionList({ exhibitions }: { exhibitions: Exhibition[] }) {
4545
}
4646

4747
export default function Index() {
48-
const { exhibitions, isLoading, errorMessage } = useExhibitions();
48+
const { exhibitions, isLoading, errorMessage, refetch } = useExhibitions();
4949
const exhibitionList: Exhibition[] = Object.values(exhibitions);
5050

5151
if (isLoading) {
5252
return <Fallback message="華展一覧を読み込み中..." />;
5353
}
5454
if (errorMessage) {
55-
return <Fallback message={errorMessage} isError />;
55+
return (
56+
<section className={styles.errorSection}>
57+
<Fallback message={errorMessage} isError />
58+
<button onClick={refetch}>再試行</button>
59+
</section>
60+
);
5661
}
5762

5863
return (

client/src/pages/scss/index.module.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@
2828
}
2929
}
3030
}
31+
32+
.errorSection {
33+
display: flex;
34+
flex-direction: column;
35+
align-items: center;
36+
justify-content: center;
37+
}

0 commit comments

Comments
 (0)