Make app data loading safe under StrictMode
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s
This commit is contained in:
parent
b470a34b2a
commit
99d916f6db
6 changed files with 207 additions and 32 deletions
|
|
@ -21,12 +21,12 @@ export const INITIAL_DIABLO4_STATE = {
|
|||
filterOptionKeys: { affixes: "" }
|
||||
};
|
||||
|
||||
export async function loadMhwildsData() {
|
||||
export async function loadMhwildsData(signal) {
|
||||
const [monstersResponse, endemicResponse, listIndexResponse, translationsResponse] = await Promise.all([
|
||||
fetch("/data/mhwilds/monsters.json"),
|
||||
fetch("/data/mhwilds/endemic_life.json"),
|
||||
fetch("/data/mhwilds/lists/index.json"),
|
||||
fetch("/data/mhwilds/i18n/fr.json")
|
||||
fetch("/data/mhwilds/monsters.json", { signal }),
|
||||
fetch("/data/mhwilds/endemic_life.json", { signal }),
|
||||
fetch("/data/mhwilds/lists/index.json", { signal }),
|
||||
fetch("/data/mhwilds/i18n/fr.json", { signal })
|
||||
]);
|
||||
|
||||
if (!monstersResponse.ok || !endemicResponse.ok || !listIndexResponse.ok || !translationsResponse.ok) {
|
||||
|
|
@ -39,7 +39,7 @@ export async function loadMhwildsData() {
|
|||
listIndexResponse.json(),
|
||||
translationsResponse.json()
|
||||
]);
|
||||
const lists = await loadGameLists("mhwilds", listIndexJson);
|
||||
const lists = await loadGameLists("mhwilds", listIndexJson, signal);
|
||||
const monsterFilterKey = Object.keys(monstersJson).find((key) => key !== "monsters") || "";
|
||||
const endemicFilterKey = Object.keys(endemicJson).find((key) => key !== "endemicLife" && key !== "aquaticLife") || "";
|
||||
|
||||
|
|
@ -62,10 +62,10 @@ export async function loadMhwildsData() {
|
|||
};
|
||||
}
|
||||
|
||||
async function loadGameLists(gameId, indexPayload) {
|
||||
async function loadGameLists(gameId, indexPayload, signal) {
|
||||
const entries = Array.isArray(indexPayload?.lists) ? indexPayload.lists : [];
|
||||
const results = await Promise.all(entries.map(async (entry) => {
|
||||
const response = await fetch(`/data/${gameId}/lists/${entry.file}`);
|
||||
const response = await fetch(`/data/${gameId}/lists/${entry.file}`, { signal });
|
||||
if (!response.ok) throw new Error(`Impossible de charger la liste ${entry.file}.`);
|
||||
const payload = await response.json();
|
||||
return normalizeGameListFile(entry, payload);
|
||||
|
|
@ -107,8 +107,8 @@ function formatListTitle(value) {
|
|||
.replace(/\b\p{L}/gu, (letter) => letter.toUpperCase());
|
||||
}
|
||||
|
||||
export async function loadDiablo4Data() {
|
||||
const response = await fetch("/data/diablo4/affixes_types.json");
|
||||
export async function loadDiablo4Data(signal) {
|
||||
const response = await fetch("/data/diablo4/affixes_types.json", { signal });
|
||||
if (!response.ok) throw new Error("Impossible de charger les données Diablo IV.");
|
||||
|
||||
const payload = await response.json();
|
||||
|
|
|
|||
|
|
@ -2,52 +2,62 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { INITIAL_DIABLO4_STATE, INITIAL_MHWILDS_STATE, loadDiablo4Data, loadMhwildsData } from "../features/games/loaders.js";
|
||||
|
||||
function useGameData(active, initialState, load) {
|
||||
const [requested, setRequested] = useState(active);
|
||||
const [data, setData] = useState(initialState);
|
||||
if (active && !requested) setRequested(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!requested) return undefined;
|
||||
const controller = new AbortController();
|
||||
load(controller.signal)
|
||||
.then((result) => {
|
||||
if (!controller.signal.aborted) setData(result);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (!controller.signal.aborted) setData({ ...initialState, loaded: true, error: error.message });
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [requested, initialState, load]);
|
||||
|
||||
// Une visite déclenche un seul chargement, conservé même si la route change.
|
||||
return requested && !data.loaded ? { ...data, loading: true } : data;
|
||||
}
|
||||
|
||||
export function useAppData(route) {
|
||||
const [siteContent, setSiteContent] = useState(null);
|
||||
const [siteContentError, setSiteContentError] = useState("");
|
||||
const [games, setGames] = useState([]);
|
||||
const [gamesError, setGamesError] = useState("");
|
||||
const [mhwilds, setMhwilds] = useState(INITIAL_MHWILDS_STATE);
|
||||
const [diablo4, setDiablo4] = useState(INITIAL_DIABLO4_STATE);
|
||||
const mhwilds = useGameData(route.startsWith("/games/mhwilds"), INITIAL_MHWILDS_STATE, loadMhwildsData);
|
||||
const diablo4 = useGameData(route.startsWith("/games/diablo4"), INITIAL_DIABLO4_STATE, loadDiablo4Data);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
Promise.all([
|
||||
fetch("/data/site.json").then((response) => {
|
||||
fetch("/data/site.json", { signal }).then((response) => {
|
||||
if (!response.ok) throw new Error("Impossible de charger le contenu du site.");
|
||||
return response.json();
|
||||
}).catch((error) => {
|
||||
setSiteContentError(error.message);
|
||||
if (!signal.aborted) setSiteContentError(error.message);
|
||||
return null;
|
||||
}),
|
||||
fetch("/data/games.json").then((response) => {
|
||||
fetch("/data/games.json", { signal }).then((response) => {
|
||||
if (!response.ok) throw new Error("Impossible de charger la liste des jeux.");
|
||||
return response.json();
|
||||
}).catch((error) => {
|
||||
setGamesError(error.message);
|
||||
if (!signal.aborted) setGamesError(error.message);
|
||||
return { games: [] };
|
||||
})
|
||||
]).then(([content, gamesPayload]) => {
|
||||
if (signal.aborted) return;
|
||||
if (content) setSiteContent(content);
|
||||
setGames(Array.isArray(gamesPayload.games) ? gamesPayload.games : []);
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!route.startsWith("/games/mhwilds") || mhwilds.loaded || mhwilds.loading) return;
|
||||
setMhwilds((state) => ({ ...state, loading: true, error: "" }));
|
||||
loadMhwildsData()
|
||||
.then(setMhwilds)
|
||||
.catch((error) => setMhwilds({ ...INITIAL_MHWILDS_STATE, loaded: true, error: error.message }));
|
||||
}, [route, mhwilds.loaded, mhwilds.loading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!route.startsWith("/games/diablo4") || diablo4.loaded || diablo4.loading) return;
|
||||
setDiablo4((state) => ({ ...state, loading: true, error: "" }));
|
||||
loadDiablo4Data()
|
||||
.then(setDiablo4)
|
||||
.catch((error) => setDiablo4({ ...INITIAL_DIABLO4_STATE, loaded: true, error: error.message }));
|
||||
}, [route, diablo4.loaded, diablo4.loading]);
|
||||
|
||||
return {
|
||||
siteContent,
|
||||
siteContentError,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue