refactor(BattleTable): extract resultMap logic and simplify table building
- Move `initResultMap` and `buildMatchGroupTable` outside the component to reduce closure dependencies. - Update `ClubEventList` to remove obsolete page key storage logic. - Add `MATCH_RESULT_MAP_KEY` constant to `utils/constants.ts`. - Refactor `useMemo` and `useCallback` hooks to rely on the extracted functions. - Ensure consistent dependency arrays in callbacks for reliable re-renders.
This commit is contained in:
parent
ce5c523efb
commit
f29974c111
@ -6,6 +6,7 @@ import styled from "styled-components";
|
|||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { ClearOutlined, EditOutlined, ShareAltOutlined } from "@ant-design/icons";
|
import { ClearOutlined, EditOutlined, ShareAltOutlined } from "@ant-design/icons";
|
||||||
import { useLocation } from "react-router";
|
import { useLocation } from "react-router";
|
||||||
|
import { MATCH_RESULT_MAP_KEY } from "../utils/constants";
|
||||||
|
|
||||||
const StyledContainer = styled(Flex)`
|
const StyledContainer = styled(Flex)`
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
@ -30,31 +31,16 @@ function getMatchKey(player1: BasePlayer, player2: BasePlayer) {
|
|||||||
return `${player1.uid}-${player2.uid}`;
|
return `${player1.uid}-${player2.uid}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BattleTable({
|
function initResultMap() {
|
||||||
players: list,
|
|
||||||
}: {
|
|
||||||
players: BasePlayer[];
|
|
||||||
}) {
|
|
||||||
const playerList = useMemo(() => list.length % 2 === 0 ? list : [...list, {
|
|
||||||
uid: '',
|
|
||||||
score: '',
|
|
||||||
name: '-',
|
|
||||||
}], [list]);
|
|
||||||
const resultMap = useMemo(() => {
|
|
||||||
const cache = localStorage.getItem('match-result-map');
|
const cache = localStorage.getItem('match-result-map');
|
||||||
const cacheEntries: [string, Result][] = cache ? Object.entries(JSON.parse(cache)) : [];
|
const cacheEntries: [string, Result][] = cache ? Object.entries(JSON.parse(cache)) : [];
|
||||||
return new Map<string, {
|
return new Map<string, {
|
||||||
winer: string,
|
winer: string,
|
||||||
score: number,
|
score: number,
|
||||||
}>(cacheEntries);
|
}>(cacheEntries);
|
||||||
}, []);
|
}
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
const buildMatchGroupTable = (list: (BasePlayer | null)[], resultMap: Map<string, Result>) => {
|
||||||
const cache = JSON.stringify(Object.fromEntries(resultMap.entries()));
|
|
||||||
localStorage.setItem('match-result-map', cache);
|
|
||||||
}
|
|
||||||
}, [resultMap]);
|
|
||||||
const buildMatchGroupTable = useCallback((list: (BasePlayer | null)[]) => {
|
|
||||||
const roundNum = list.length - 1;
|
const roundNum = list.length - 1;
|
||||||
const dataList = cloneDeep(list);
|
const dataList = cloneDeep(list);
|
||||||
const roundTable = new Array(roundNum).fill(0).map((_, i) => {
|
const roundTable = new Array(roundNum).fill(0).map((_, i) => {
|
||||||
@ -76,8 +62,22 @@ function BattleTable({
|
|||||||
});
|
});
|
||||||
return cloneDeep([left, right]);
|
return cloneDeep([left, right]);
|
||||||
});
|
});
|
||||||
|
const cache = JSON.stringify(Object.fromEntries(resultMap.entries()));
|
||||||
|
localStorage.setItem(MATCH_RESULT_MAP_KEY, cache);
|
||||||
return roundTable;
|
return roundTable;
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
|
function BattleTable({
|
||||||
|
players: list,
|
||||||
|
}: {
|
||||||
|
players: BasePlayer[];
|
||||||
|
}) {
|
||||||
|
const playerList = useMemo(() => list.length % 2 === 0 ? list : [...list, {
|
||||||
|
uid: '',
|
||||||
|
score: '',
|
||||||
|
name: '-',
|
||||||
|
}], [list]);
|
||||||
|
const resultMap = useMemo(() => initResultMap(), []);
|
||||||
const [matchGroupTable, setMatchGroupTable] = useState<ReturnType<typeof buildMatchGroupTable>>([]);
|
const [matchGroupTable, setMatchGroupTable] = useState<ReturnType<typeof buildMatchGroupTable>>([]);
|
||||||
const matchKeys = useMemo(() => {
|
const matchKeys = useMemo(() => {
|
||||||
const keys: string[] = [];
|
const keys: string[] = [];
|
||||||
@ -99,16 +99,16 @@ function BattleTable({
|
|||||||
} else {
|
} else {
|
||||||
resultMap.set(key, { winer: winer?.uid!, score });
|
resultMap.set(key, { winer: winer?.uid!, score });
|
||||||
}
|
}
|
||||||
setMatchGroupTable(buildMatchGroupTable(playerList));
|
setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
|
||||||
}, []);
|
}, [playerList, resultMap]);
|
||||||
const handleClear = useCallback((left?: (BasePlayer | null | undefined)[], right?: (BasePlayer | null | undefined)[]) => {
|
const handleClear = useCallback((left?: (BasePlayer | null | undefined)[], right?: (BasePlayer | null | undefined)[]) => {
|
||||||
left?.forEach((l, i) => {
|
left?.forEach((l, i) => {
|
||||||
const r = right?.[i];
|
const r = right?.[i];
|
||||||
const key = getMatchKey(l!, r!);
|
const key = getMatchKey(l!, r!);
|
||||||
resultMap.delete(key);
|
resultMap.delete(key);
|
||||||
});
|
});
|
||||||
setMatchGroupTable(buildMatchGroupTable(playerList));
|
setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
|
||||||
}, [matchGroupTable, playerList]);
|
}, [playerList, resultMap]);
|
||||||
const handleClearAll = useCallback(() => {
|
const handleClearAll = useCallback(() => {
|
||||||
matchGroupTable.forEach(([left, right]) => {
|
matchGroupTable.forEach(([left, right]) => {
|
||||||
left?.forEach((l, i) => {
|
left?.forEach((l, i) => {
|
||||||
@ -117,8 +117,8 @@ function BattleTable({
|
|||||||
resultMap.delete(key);
|
resultMap.delete(key);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
setMatchGroupTable(buildMatchGroupTable(playerList));
|
setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
|
||||||
}, [matchGroupTable, playerList]);
|
}, [matchGroupTable, playerList, resultMap]);
|
||||||
const scoreDiff = useMemo(() => {
|
const scoreDiff = useMemo(() => {
|
||||||
const [left = [], right = []] = matchGroupTable?.[matchGroupTable.length - 1] ?? [];
|
const [left = [], right = []] = matchGroupTable?.[matchGroupTable.length - 1] ?? [];
|
||||||
const newScoreMap = Object.fromEntries([...left, ...right].map(e => [e?.uid, e?.score]));
|
const newScoreMap = Object.fromEntries([...left, ...right].map(e => [e?.uid, e?.score]));
|
||||||
@ -154,9 +154,9 @@ function BattleTable({
|
|||||||
setImportModalVisible(false);
|
setImportModalVisible(false);
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const roundTable = buildMatchGroupTable(playerList);
|
const roundTable = buildMatchGroupTable(playerList, resultMap);
|
||||||
setMatchGroupTable(roundTable);
|
setMatchGroupTable(roundTable);
|
||||||
}, [playerList]);
|
}, [playerList, resultMap]);
|
||||||
const [shareCode, setShareCode] = useState('');
|
const [shareCode, setShareCode] = useState('');
|
||||||
const handleImportCode = useCallback(async () => {
|
const handleImportCode = useCallback(async () => {
|
||||||
const data: Record<string, Result> = await fetch(`/api/battle/${eventId}?code=${shareCode}`)
|
const data: Record<string, Result> = await fetch(`/api/battle/${eventId}?code=${shareCode}`)
|
||||||
@ -166,7 +166,7 @@ function BattleTable({
|
|||||||
const { winer = '', score = 0 } = v ?? {};
|
const { winer = '', score = 0 } = v ?? {};
|
||||||
resultMap.set(k, { winer, score });
|
resultMap.set(k, { winer, score });
|
||||||
});
|
});
|
||||||
setMatchGroupTable(buildMatchGroupTable(playerList));
|
setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
|
||||||
setImportModalVisible(false);
|
setImportModalVisible(false);
|
||||||
}, [shareCode, playerList]);
|
}, [shareCode, playerList]);
|
||||||
// console.debug('matchGroupTable', matchGroupTable, gameResultMap);
|
// console.debug('matchGroupTable', matchGroupTable, gameResultMap);
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|||||||
import { EventCard } from "./EventCard";
|
import { EventCard } from "./EventCard";
|
||||||
import { useRequest } from "ahooks";
|
import { useRequest } from "ahooks";
|
||||||
import { CalendarOutlined } from "@ant-design/icons";
|
import { CalendarOutlined } from "@ant-design/icons";
|
||||||
import { STORE_PAGE_LIST_KEY } from "../utils/constants";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
clubId: string;
|
clubId: string;
|
||||||
@ -44,11 +43,6 @@ export const ClubEvenList = (props: Props) => {
|
|||||||
}, [showFinishedEvents, requestEvents.data?.data]);
|
}, [showFinishedEvents, requestEvents.data?.data]);
|
||||||
const onPageInit = useCallback(async () => {
|
const onPageInit = useCallback(async () => {
|
||||||
const storePageKey = getStorageKey(props.clubId);
|
const storePageKey = getStorageKey(props.clubId);
|
||||||
const keys: string[] = JSON.parse(localStorage.getItem(STORE_PAGE_LIST_KEY) ?? '[]');
|
|
||||||
if (!keys.includes(storePageKey)) {
|
|
||||||
keys.push(storePageKey);
|
|
||||||
localStorage.setItem(STORE_PAGE_LIST_KEY, JSON.stringify(keys));
|
|
||||||
}
|
|
||||||
const prePage = Number(sessionStorage.getItem(storePageKey)) || 1;
|
const prePage = Number(sessionStorage.getItem(storePageKey)) || 1;
|
||||||
const data = await requestEvents.runAsync(props.clubId, prePage).then(res => res.data);
|
const data = await requestEvents.runAsync(props.clubId, prePage).then(res => res.data);
|
||||||
setPage(prePage);
|
setPage(prePage);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export const LOGTO_RESOURCE = 'https://tt.ksr.la';
|
export const LOGTO_RESOURCE = 'https://tt.ksr.la';
|
||||||
export const CLUB_SELECTOR_KEY = 'CLUB_SELECTOR';
|
export const CLUB_SELECTOR_KEY = 'CLUB_SELECTOR';
|
||||||
export const STORE_PAGE_LIST_KEY = 'events-page-keys';
|
export const STORE_PAGE_LIST_KEY = 'events-page-keys';
|
||||||
|
export const MATCH_RESULT_MAP_KEY = 'match-result-map';
|
||||||
Loading…
Reference in New Issue
Block a user