-
[7일차] 셔플(Suffle) 기능 구현 및 길어진 Promise 코드를 async/await 로 정리프로젝트 개발/뮤직플레이어 웹앱 2021. 2. 12. 20:41반응형
어제 작성한 소스코드로 반복재생, 다음 음악 재생, 음악 파일이 저장되어있지 않은 경우 storage에서 내려받는 기능 구현까지 주요 기능은 어느정도 갖춰지게 되었다. 남은건 셔플(Suffle) 기능과 재생목록화면, 메인 재생화면에 대한 UI 디자인 등이 남은 듯 하다.
오늘은 두 가지를 처리했다. 하난 셔플, 다른 하나는 길어진 소스코드에 대한 정리이다.
셔플
셔플 기능은 간단하게 구현 가능했다. 물론 이부분도 약간의 뻘짓이 들어 갔었기 때문에 별도의 포스트로 정리하였다.
https://ddochea.tistory.com/97
[React Hook] 상태 훅(State Hook)을 내부함수로 정의할 경우 유의사항
이 소스 자체가 올바르다고 보긴 어렵겠지만 나중에 또 뻘짓할수도 있는점을 대비해 정리한 글 useEffect(() => { console.log(`playIndexes : ${playIndexes}`); }, [playIndexes]); useEffect(() => { if(isSuff..
ddochea.tistory.com
원하는 목적은 셔플기능을 활성화 할때, 듣고있는 현재 음악을 제외한 나머지 Index의 배열순서를 랜덤으로 돌리게 하고 싶었다. 그냥 playIndexes 전체를 랜덤하게 돌린다 할지라도, 듣고 있는 음악이 갑자기 꺼진다거나 처음으로 재생되는 일이 발생하는 건 아니지만, 전체 랜덤이 되면 바로 다음 순서에서 중복 재생될 수 있기 때문에 아래와 같이 구현하게 되었다.
useEffect(() => { if(isSuffle) { // 현재 듣고 있는 index를 제외하고 Array 내 Index 번호들을 랜덤 순서로 변경 const p = playIndexes; const rndTargets = [...p.slice(0, currentPlayIdx), ...p.slice(currentPlayIdx + 1, p.length)].sort(p => Math.random() - Math.random()); const result = [...rndTargets.slice(0, currentPlayIdx), p[currentPlayIdx], ...rndTargets.slice(currentPlayIdx, p.length)]; console.log(`suffle result: ${result}`); setPlayIndexes(result); } else { setPlayIndexes(p => p.sort()); } }, [isSuffle]);
결과는 만족스러웠다. 바로 Deploy 시킨 뒤 실제로 사용했다.
currentPlayIdx Effect Hook에 대한 소스코드 정리
어제 진행했던 코드에서 음악 재생 완료 후 다음 음악으로 재생하는 Effect Hook [currentPlayIdx] 에 대한 소스코드가 상당히 길었다.
useEffect(() => { if(currentPlayIdx !== -1){ const audio = audioRef.current; URL.revokeObjectURL(audio.src); const key = playList[playIndexes[currentPlayIdx]]; localforage.getItem(key) .then(item => { if(item) { play(item); } else { return storage.child(key).getDownloadURL() .then(url => { if(url) { return fetch(url); } }) .then(res => { if(res) { return res.blob(); } }) .then(blob => { if(blob) { console.log(`call blob`); console.log(blob); localforage.setItem(key, blob); play(blob); } }); } }); const play = (item : any) => { if(item){ audio.src = URL.createObjectURL(item); if(isPlay) audio.play(); } } } }, [currentPlayIdx])
동작 자체는 이상없으나 상당히 불편했다. 그래서 아래와 같이 수정하였다.
useEffect(() => { if(currentPlayIdx !== -1){ const audio = audioRef.current; (async () => { URL.revokeObjectURL(audio.src); const key = playList[playIndexes[currentPlayIdx]]; const item : any = await localforage.getItem(key); if(item) { audio.src = URL.createObjectURL(item); if(isPlay) audio.play(); } else { try { const url = await storage.child(key).getDownloadURL(); const res = await fetch(url); const blob = await res.blob(); localforage.setItem(key, blob); audio.src = URL.createObjectURL(blob); if(isPlay) audio.play(); } catch(e) { console.error(e); } } setCurrentPlayTitle(key); })(); } }, [currentPlayIdx])
많이 줄어든건 아니지만 어느정도 만족스럽긴 하다. 동작은 두 소스 모두 이상없이 동작했다.
이것으로 주요기능 구현은 모두 마쳤다.
내일 이시간 이후로는 UI 위주로 수정하면 될 것 같다.
반응형'프로젝트 개발 > 뮤직플레이어 웹앱' 카테고리의 다른 글
[9일차] nailed it! 구현 마무리 및 해결되지 않은 문제 (2) 2021.02.14 [8일차] React Prop를 이용해 음악 재생 리스트 하위 컴포넌트 구현 (0) 2021.02.13 [5~6일차] 주요 오류 발생사항 수정 (0) 2021.02.12 [3~4일차] firebase Authentication를 이용한 OAuth 방식 로그인/로그아웃 구현 진행 (0) 2021.02.09 [1~2일차] 기술스택 선정 및 Material-UI 로 대략적인 화면 구성 (0) 2021.02.07