계발하는 개발자

[JS] 조건을 만족하는 배열 요소의 인덱스 반환 - findIndex() 메서드 본문

📌 Language/Javascript

[JS] 조건을 만족하는 배열 요소의 인덱스 반환 - findIndex() 메서드

dev_genie 2023. 10. 31. 15:57
findIndex() 메서드란?
주어진 판별 조건을 만족하는 배열의 첫 번째 요소에 대한 인덱스를 반환하는 메서드로,
만족하는 요소가 없는 경우 -1을 반환한다.

 

아래 공식문서에서도 설명이 자세하게 나와있다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

 

이번에 next.js로 뮤직플레이어 기능을 구현하면서 findIndex 메서드를 요긴하게 활용한 것 같다.

해당 프로젝트에 대한 회고 겸 findIndex 메서드 정리차 글로도 남겨본다. 

 

플레이리스트 선택시 해당 음원 가사로 변경

플레이리스트에 담긴 li 클릭시 해당 음원의 가사로 변경되도록 해야했다.

 

내가 클릭한 플레이리스트 타이틀명과 배열 tit 값이 일치할 경우에

해당 배열 순번의 lyrics 값을 출력하도록 하면 어떨까?

 

아래같이 하면 records 배열의 tit 속성값이 내가 클릭한 li 타이틀과 일치하는 때의

배열의 인덱스가 반환되게 된다.

 

pickIdx 값을 콘솔에 찍어보면 2 라는 배열 인덱스값이 반환되는 걸 확인할 수 있다.

I DO 음원을 클릭할 경우에는 1 이라는 값이 반환된다.

 

아래는 전체 코드다.

<div className="p_lyrics"></div>
<div id="play-list">
    <ul></ul>
</div>

/* 더미데이터 */
import { artists, headlines, records } from "../data/hcode";

// 곡 선택시 해당 음원 재생
const clkList = () => {
    const listAll = $("#play-list li");
    $(listAll).on("click", function () {
        $(this).toggleClass("on").siblings().removeClass("on");
        // 리스트 이미지
        let listImg = $(this).find(".imgarea > img").attr("src");
        // 리스트 타이틀
        let listTxt = $(this).find(".txtarea > strong").text();
        // 리스트 곡
        let listAud = $(this).find("audio").attr("src");
        // 가사창
        const lyrics = $(".p_lyrics");

        // 일치하는 데이터 순번 구하기
        const pickIdx = records.findIndex(hd => hd.tit === listTxt);

        if (pickIdx !== -1) {
            // 가사 변경
            lyrics.html(records[pickIdx].lyrics);
        }

        // redux 상태 업데이트
        dispatch(setImg(listImg));
        dispatch(setTit(listTxt));
        dispatch(setAudio(listAud));

        if ($(this).hasClass("on")) {
            showList();
        }
    });
};

 

플레이리스트 담기 취소시 로컬스토리지에서 삭제

비슷한 다른 예로 findIndex 메서드를 사용해서 로컬스토리지에 담긴 특정 순번 데이터도 삭제할 수 있다.

 

음반리스트에서 + 버튼을 클릭하여 해당 곡 데이터를 로컬스토리지에 담았고,

이 데이터는 로컬스토리지 KEY song_item 배열의 3번에 추가된다. 

 

+ 버튼 체크 해제시 removeIndex 값을 콘솔에 찍어보니 3 이라는 값이 반환됐다.

 

로컬스토리지에서 파싱한 배열 데이터의 3번 인덱스 값을 삭제한 후

그 결과를 로컬스토리지 song_item KEY 값에 반영시키니 아래처럼 나온다.

 

플레이리스트에 출력되는 li는 로컬스토리지에 보관된 값에서 가져오고 있으므로

따라서 플레이리스트 에서도 해당 데이터가 삭제되어 보이게 된다.

 

아래는 전체 코드다.

// 음원 플레이리스트 추가
const addSong = () => {
    let arr: any = [];
    const addbtn = document.querySelectorAll(".addbtn");
    const playList = document.querySelector("#play-list > ul") as HTMLElement;

    // 로컬스토리지 음반리스트 셋팅
    const saveList: any[] = JSON.parse(localStorage.getItem("song_item") || "[]");

    addbtn.forEach((el, i) => {
        el.addEventListener("click", function (this: HTMLElement) {
            this.classList.toggle("active");

            // 중복데이터 선별 변수(true/false)
            const isB = saveList.some(item => item.tit === records[i].tit);
            console.log("중복 판별 여부:", isB);

            // 버튼 클래스 on & 데이터 중복 아닐시
            if (this.classList.contains("active") && !isB) {
                console.log("플레이리스트 추가");

                const list = { tit: records[i].tit, alb: records[i].alb, img: records[i].isrc, time: records[i].time, song: records[i].msrc };

                // 배열에 값 보내기
                saveList.push(list);
                localStorage.setItem("song_item", JSON.stringify(saveList));
                updateList();
            }
            // 버튼 클래스 off시
            else if (!this.classList.contains("active")) {
                console.log("플레이리스트 삭제");

                // 해당 곡 로컬스에서 제거
                const removeIndex = saveList.findIndex(item => item.tit === records[i].tit);
                if (removeIndex !== -1) {
                    saveList.splice(removeIndex, 1);
                    localStorage.setItem("song_item", JSON.stringify(saveList));
                }
                updateList();
            }
        });
    });

    // 음원 목록 업데이트
    const updateList = () => {
        playList.innerHTML = "";
        saveList.forEach((item, i) => {
            const listItem = `
                <li data-index=${i}>
                    <div class="imgarea">
                        <img src=${item.img} alt=${item.tit}>
                    </div>
                    <div class="txtarea">
                        <strong>${item.tit}</strong>
                        <em>${item.alb}</em>
                    </div>
                    <span data-duration=${item.time}>${item.time}</span>
                    <audio src=${item.song}></audio>
                </li>
            `;
            playList.insertAdjacentHTML("beforeend", listItem);
        });
    };
    updateList();
};
LIST
profile

dev_genie

@dev_genie

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!