Skip to content

Commit

Permalink
refctor: SongDetailListPage 내 로직 custom hook 분리
Browse files Browse the repository at this point in the history
1. 첫 entries fetch 담당 hook
2. 이후 extra Fetch 담당 hook
  • Loading branch information
Creative-Lee committed Nov 3, 2023
1 parent da53a35 commit 1ef030a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 74 deletions.
70 changes: 70 additions & 0 deletions frontend/src/features/songs/hooks/useExtraSongDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useCallback, useRef } from 'react';
import useExtraFetch from '@/shared/hooks/useExtraFetch';
import useValidParams from '@/shared/hooks/useValidParams';
import createObserver from '@/shared/utils/createObserver';
import { getExtraNextSongDetails, getExtraPrevSongDetails } from '../remotes/songs';
import type { Genre } from '../types/Song.type';

const useExtraSongDetail = () => {
const { genre: genreParams } = useValidParams();

const { data: extraPrevSongDetails, fetchData: fetchExtraPrevSongDetails } = useExtraFetch(
getExtraPrevSongDetails,
'prev'
);

const { data: extraNextSongDetails, fetchData: fetchExtraNextSongDetails } = useExtraFetch(
getExtraNextSongDetails,
'next'
);

const prevObserverRef = useRef<IntersectionObserver | null>(null);
const nextObserverRef = useRef<IntersectionObserver | null>(null);

const getExtraPrevSongDetailsOnObserve: React.RefCallback<HTMLDivElement> = useCallback((dom) => {
if (dom === null) {
prevObserverRef.current?.disconnect();
return;
}

prevObserverRef.current = createObserver(() =>
fetchExtraPrevSongDetails(getFirstSongId(dom), genreParams as Genre)
);

prevObserverRef.current.observe(dom);
}, []);

Check warning on line 35 in frontend/src/features/songs/hooks/useExtraSongDetail.ts

View workflow job for this annotation

GitHub Actions / test

React Hook useCallback has missing dependencies: 'fetchExtraPrevSongDetails' and 'genreParams'. Either include them or remove the dependency array

const getExtraNextSongDetailsOnObserve: React.RefCallback<HTMLDivElement> = useCallback((dom) => {
if (dom === null) {
nextObserverRef.current?.disconnect();
return;
}

nextObserverRef.current = createObserver(() =>
fetchExtraNextSongDetails(getLastSongId(dom), genreParams as Genre)
);

nextObserverRef.current.observe(dom);
}, []);

Check warning on line 48 in frontend/src/features/songs/hooks/useExtraSongDetail.ts

View workflow job for this annotation

GitHub Actions / test

React Hook useCallback has missing dependencies: 'fetchExtraNextSongDetails' and 'genreParams'. Either include them or remove the dependency array

const getFirstSongId = (dom: HTMLDivElement) => {
const firstSongId = dom.nextElementSibling?.getAttribute('data-song-id') as string;

return Number(firstSongId);
};

const getLastSongId = (dom: HTMLDivElement) => {
const lastSongId = dom.previousElementSibling?.getAttribute('data-song-id') as string;

return Number(lastSongId);
};

return {
extraPrevSongDetails,
extraNextSongDetails,
getExtraPrevSongDetailsOnObserve,
getExtraNextSongDetailsOnObserve,
};
};

export default useExtraSongDetail;
22 changes: 22 additions & 0 deletions frontend/src/features/songs/hooks/useSongDetailEntries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useLayoutEffect, useRef } from 'react';
import useFetch from '@/shared/hooks/useFetch';
import useValidParams from '@/shared/hooks/useValidParams';
import { getSongDetailEntries } from '../remotes/songs';
import type { Genre } from '../types/Song.type';

const useSongDetailEntries = () => {
const { id: songIdParams, genre: genreParams } = useValidParams();
const currentSongDetailItemRef = useRef<HTMLDivElement>(null);

const { data: songDetailEntries } = useFetch(() =>
getSongDetailEntries(Number(songIdParams), genreParams as Genre)
);

useLayoutEffect(() => {
currentSongDetailItemRef.current?.scrollIntoView({ behavior: 'instant', block: 'start' });
}, [songDetailEntries]);

return { songDetailEntries, currentSongDetailItemRef };
};

export default useSongDetailEntries;
86 changes: 12 additions & 74 deletions frontend/src/pages/SongDetailListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,97 +1,35 @@
import { useCallback, useLayoutEffect, useRef } from 'react';
import { styled } from 'styled-components';
import swipeUpDown from '@/assets/icon/swipe-up-down.svg';
import SongDetailItem from '@/features/songs/components/SongDetailItem';
import {
getExtraNextSongDetails,
getExtraPrevSongDetails,
getSongDetailEntries,
} from '@/features/songs/remotes/songs';
import useExtraSongDetail from '@/features/songs/hooks/useExtraSongDetail';
import useSongDetailEntries from '@/features/songs/hooks/useSongDetailEntries';
import useModal from '@/shared/components/Modal/hooks/useModal';
import Modal from '@/shared/components/Modal/Modal';
import Spacing from '@/shared/components/Spacing';
import useExtraFetch from '@/shared/hooks/useExtraFetch';
import useFetch from '@/shared/hooks/useFetch';
import useLocalStorage from '@/shared/hooks/useLocalStorage';
import useValidParams from '@/shared/hooks/useValidParams';
import createObserver from '@/shared/utils/createObserver';
import type { Genre } from '@/features/songs/types/Song.type';

const SongDetailListPage = () => {
const { isOpen, closeModal } = useModal(true);
const [onboarding, setOnboarding] = useLocalStorage<boolean>('onboarding', true);

const { id: songIdParams, genre: genreParams } = useValidParams();
const { data: songDetailEntries } = useFetch(() =>
getSongDetailEntries(Number(songIdParams), genreParams as Genre)
);

const { data: extraPrevSongDetails, fetchData: fetchExtraPrevSongDetails } = useExtraFetch(
getExtraPrevSongDetails,
'prev'
);

const { data: extraNextSongDetails, fetchData: fetchExtraNextSongDetails } = useExtraFetch(
getExtraNextSongDetails,
'next'
);

const prevObserverRef = useRef<IntersectionObserver | null>(null);
const nextObserverRef = useRef<IntersectionObserver | null>(null);

const getExtraPrevSongDetailsOnObserve: React.RefCallback<HTMLDivElement> = useCallback((dom) => {
if (dom === null) {
prevObserverRef.current?.disconnect();
return;
}

prevObserverRef.current = createObserver(() =>
fetchExtraPrevSongDetails(getFirstSongId(dom), genreParams as Genre)
);

prevObserverRef.current.observe(dom);
}, []);

const getExtraNextSongDetailsOnObserve: React.RefCallback<HTMLDivElement> = useCallback((dom) => {
if (dom === null) {
nextObserverRef.current?.disconnect();
return;
}

nextObserverRef.current = createObserver(() =>
fetchExtraNextSongDetails(getLastSongId(dom), genreParams as Genre)
);
const { songDetailEntries, currentSongDetailItemRef } = useSongDetailEntries();

nextObserverRef.current.observe(dom);
}, []);
const {
extraPrevSongDetails,
extraNextSongDetails,
getExtraPrevSongDetailsOnObserve,
getExtraNextSongDetailsOnObserve,
} = useExtraSongDetail();

const itemRef = useRef<HTMLDivElement>(null);
if (!songDetailEntries) return null;

const getFirstSongId = (dom: HTMLDivElement) => {
const firstSongId = dom.nextElementSibling?.getAttribute('data-song-id') as string;

return Number(firstSongId);
};

const getLastSongId = (dom: HTMLDivElement) => {
const lastSongId = dom.previousElementSibling?.getAttribute('data-song-id') as string;

return Number(lastSongId);
};
const { prevSongs, currentSong, nextSongs } = songDetailEntries;

const closeCoachMark = () => {
setOnboarding(false);
closeModal();
};

useLayoutEffect(() => {
itemRef.current?.scrollIntoView({ behavior: 'instant', block: 'start' });
}, [songDetailEntries]);

if (!songDetailEntries) return;

const { prevSongs, currentSong, nextSongs } = songDetailEntries;

return (
<>
{onboarding && (
Expand Down Expand Up @@ -122,7 +60,7 @@ const SongDetailListPage = () => {
<SongDetailItem key={prevSongDetail.id} {...prevSongDetail} />
))}

<SongDetailItem ref={itemRef} key={currentSong.id} {...currentSong} />
<SongDetailItem ref={currentSongDetailItemRef} key={currentSong.id} {...currentSong} />

{nextSongs.map((nextSongDetail) => (
<SongDetailItem key={nextSongDetail.id} {...nextSongDetail} />
Expand Down

0 comments on commit 1ef030a

Please sign in to comment.