Custom Hooks
Relevant source files
The following files were used as context for generating this wiki page:
Custom hooks in the Endfield-Pomodoro project are a core part of its architecture, encapsulating reusable stateful logic. They are used to separate concerns, making components cleaner and more focused on rendering UI. The hooks manage a variety of functionalities, including data fetching for online music, local and online audio playback state, UI measurements, and internationalization.
This approach aligns with modern React development practices, promoting code reuse and maintainability. Key logic for features like the Audio Player and responsive UI elements is abstracted into these hooks, which are then consumed by the relevant components.
Sources: README.md:104-108, src/App.tsx, src/components/AudioPlayer.tsx
Data Fetching Hooks
useMusicData
This hook is responsible for fetching online music playlist data from various music platforms. It features a fault-tolerant mechanism that cycles through multiple API adapters if one fails.
Sources: src/hooks/useMusicData.ts
Parameters
| Parameter | Type | Description |
|---|---|---|
server | string | The music platform (e.g., 'netease'). |
type | string | The type of resource (e.g., 'playlist'). |
id | string | The ID of the resource (e.g., playlist ID). |
Sources: src/hooks/useMusicData.ts:20-24
Return Value
| Key | Type | Description |
|---|---|---|
audioList | MusicTrack[] | An array of track objects. |
loading | boolean | true while data is being fetched. |
error | string | null | An error message if all APIs fail. |
Sources: src/hooks/useMusicData.ts:37-39
Data Flow
The hook initiates a fetch request after a short delay (API_FETCH_DELAY_MS). It iterates through a list of API adapters, attempting to fetch and parse the data with each one. The process includes a timeout for each request (API_TIMEOUT_MS) and can be aborted if the component unmounts or the parameters change.
The following diagram illustrates the data fetching flow within useMusicData.
Sources: src/hooks/useMusicData.ts:41-94
Key Data Structures
The hook returns an array of MusicTrack objects.
export interface MusicTrack {
name: string;
artist: string;
url: string;
cover: string;
lrc: string;
theme?: string;
}
Sources: src/hooks/useMusicData.ts:6-14
Audio Player Hooks
The application uses separate custom hooks to manage the logic for local and online audio playback, which are consumed by the AudioPlayer component.
Sources: src/components/AudioPlayer.tsx:18-21, README.md:106-108
useLocalPlayer
This hook encapsulates all the logic for the local audio player. It manages the playlist, playback state, audio metadata parsing, and user interactions. Its API is inferred from its usage within the AudioPlayer.tsx component.
Sources: src/components/AudioPlayer.tsx:21
Inferred API
The useLocalPlayer hook returns an object containing state variables and handler functions.
| Key | Type | Description |
|---|---|---|
isPlaying | boolean | true if a track is currently playing. |
currentTime | number | The current playback time in seconds. |
duration | number | The total duration of the current track in seconds. |
volume | number | The current volume level (0.0 to 1.0). |
currentTrack | { name, artist, coverUrl } | null | Metadata of the currently loaded track. |
playlist | Track[] | An array of all tracks in the local playlist. |
currentIndex | number | The index of the current track in the playlist. |
playMode | PlayMode | The current playback mode ('sequence', 'loop', 'random'). |
isLoading | boolean | true when a new track is being loaded. |
addFiles | (files: File[]) => void | Adds new audio files to the playlist. |
removeTrack | (index: number) => void | Removes a track from the playlist by its index. |
clearPlaylist | () => void | Clears the entire playlist. |
playTrack | (index: number) => void | Plays a specific track from the playlist by its index. |
togglePlay | () => void | Toggles the playback state between play and pause. |
handleNext | () => void | Skips to the next track based on the current play mode. |
handlePrev | () => void | Goes to the previous track. |
seek | (time: number) => void | Seeks to a specific time in the current track. |
setVolume | (volume: number) => void | Sets the player volume. |
toggleMode | () => void | Toggles between different play modes. |
Sources: src/components/AudioPlayer.tsx:89-110, src/components/AudioPlayer.tsx:162-184
useOnlinePlayer
The project structure indicates the existence of a useOnlinePlayer.ts hook. This hook is responsible for managing the state and logic for playing music from online sources, likely using the useMusicData hook internally to fetch the playlist.
Sources: README.md:108
UI & Utility Hooks
useFooterHeight
This hook is used to dynamically measure the height of the application's footer. This is crucial for positioning other UI elements, such as the MikuDecorations, correctly relative to the bottom of the viewport.
It returns a ref (footerRef) to be attached to the footer element and a state variable (footerHeight) that holds the measured height in pixels.
Sources: src/App.tsx:114, src/components/MikuDecorations.tsx:128-131
useIsMobile
This hook detects whether the application is running on a mobile device. It is used to conditionally render or disable features that are not suitable for mobile, such as mouse-tracking effects. It returns a single boolean value.
Sources: src/components/MikuDecorations.tsx:75-77
useTranslation
This function, located in i18n.ts, acts as a hook for providing internationalization (i18n). It takes the current language ('EN' or 'CN') as an argument and returns a translator function t. The t function accepts a translation key and returns the corresponding string in the selected language.
The following sequence diagram shows how a component gets and uses a translated string.
Sources: src/utils/i18n.ts:221-225, src/App.tsx:116
Conclusion
The custom hooks in Endfield-Pomodoro are fundamental to its modular and maintainable design. They effectively abstract complex logic related to data fetching, media control, and UI responsiveness, allowing components to remain simple and declarative. This separation of concerns is a key architectural strength of the project.