Files
harukin-expo-dev-env 19b280a467 feat: implement startup icon font preloading and improve loading checks in AppContainer
refactor: simplify CarouselTypeChanger by removing redundant onPressIn handlers
fix: enhance MenuLED memoization for better performance
refactor: optimize EachData component with useMemo for derived values
fix: improve error handling in TrainPosition data fetching
refactor: streamline AddressText component's API call with abort controller
refactor: update Menu component to manage selected station state more effectively
2026-09-13 15:09:37 +09:00

121 lines
3.4 KiB
TypeScript

import React, { useCallback, useEffect, useRef, useState } from "react";
import { InteractionManager, Text, View } from "react-native";
import LottieView from "lottie-react-native";
import { useResponsive } from "@/lib/responsive";
import { useThemeColors } from "@/lib/theme";
import type { StationProps } from "@/lib/CommonTypes";
import { LED_vision } from "@/components/発車時刻表/LED_vidion";
import { LEDFrame } from "@/components/発車時刻表/LED_Vision_Component/LEDFrame";
type MenuLEDProps = {
station: StationProps[];
};
type PreparedLED = {
key: string;
station: StationProps[];
};
const MemoizedLEDVision = React.memo(LED_vision);
const getStationRenderKey = (station: StationProps[]) =>
station
.map(({ StationNumber, Station_JP, lat, lng }) =>
[StationNumber ?? "", Station_JP, lat, lng].join(":"),
)
.join("|");
const MenuLEDComponent = ({ station }: MenuLEDProps) => {
const { colors, fixed } = useThemeColors();
const { fontScale, verticalScale } = useResponsive();
const stationKey = getStationRenderKey(station);
const latestStationRef = useRef(station);
latestStationRef.current = station;
const [preparedLED, setPreparedLED] = useState<PreparedLED>(() => ({
key: stationKey,
station,
}));
const [isLEDReady, setIsLEDReady] = useState(true);
const activeStation =
preparedLED.key === stationKey ? preparedLED.station : null;
useEffect(() => {
if (preparedLED.key === stationKey) return;
let cancelled = false;
setIsLEDReady(false);
const task = InteractionManager.runAfterInteractions(() => {
if (cancelled) return;
setPreparedLED({
key: stationKey,
station: latestStationRef.current,
});
});
return () => {
cancelled = true;
task.cancel();
};
}, [preparedLED.key, stationKey]);
const handleContentReady = useCallback(() => {
setIsLEDReady(true);
}, []);
const showLoading = activeStation === null || !isLEDReady;
const loadingMinHeight = verticalScale(180);
return (
<LEDFrame style={{ position: "relative", minHeight: loadingMinHeight }}>
{activeStation && (
<MemoizedLEDVision
station={activeStation}
embedded
onContentReady={handleContentReady}
/>
)}
{showLoading && (
<View
pointerEvents="none"
style={{
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
minHeight: loadingMinHeight,
alignItems: "center",
justifyContent: "center",
backgroundColor: fixed.ledBackground,
zIndex: 1,
}}
>
<LottieView
autoPlay
loop
style={{ width: 80, height: 80 }}
source={require("@/assets/51690-loading-diamonds.json")}
/>
<Text
style={{
marginTop: 12,
color: "#fff",
fontSize: fontScale(14),
}}
>
LEDを読み込み中
</Text>
</View>
)}
</LEDFrame>
);
};
const areMenuLEDPropsEqual = (
previous: MenuLEDProps,
next: MenuLEDProps,
) => getStationRenderKey(previous.station) === getStationRenderKey(next.station);
export const MenuLED = React.memo(MenuLEDComponent, areMenuLEDPropsEqual);
MenuLED.displayName = "MenuLED";