Coding History

리액트! (JS Filter)

BlackBirdIT 2024. 9. 24. 10:43

이거 상당히 재밌는 것 같다. (여담)

console.clear();

import React, { useState } from "https://cdn.skypack.dev/react@18";
import ReactDOM from "https://cdn.skypack.dev/react-dom@18";

const App = () => {
    const [number, setNumber] = useState(0);
    const [recordNums, setRecordNums] = useState([]);

    const saveRecord = () => {
        setNumber(0);
        setRecordNums([...recordNums, number]);
    };

    return (
        <>
            <div>숫자 : {number}</div>
            {recordNums.length == 0 ? (
                <div>기록 없음</div>
            ) : (
                <>
                    <h3>기록</h3>
                    <ul>
                        {recordNums.map(recordNum => <li>{recordNum}</li>)}
                    </ul>
                    <hr/>
                    <h3>기록(역순)</h3>
                    <ul>
                        {[...recordNums].reverse().map(recordNum => <li>{recordNum}</li>)}
                    </ul>
                </>
            )}

            <div>
                <button
                    onClick={() => {
                        setNumber(number + 1);
                    }}
                >
                    증가
                </button>
                &nbsp;
                <button
                    onClick={() => {
                        setNumber(number - 1);
                    }}
                >
                    감소
                </button>
                &nbsp;
                <button onClick={saveRecord}>기록</button>
            </div>
        </>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));

우선 코드고.

이렇게 실행하는데 이걸 보고

    function fetchPlaylists() {

        console.log('Access Token:', accessToken);
        console.log('Provider:', provider);

        if (!accessToken || provider === "google") {
            document.getElementById('playlist-list').innerHTML = "<p>Spotify 로그인 후 플레이리스트를 볼 수 있습니다.</p>";
            return;
        }

        console.log('Starting fetch for playlists...');

        // lofi 및 chillhop 키워드로 플레이리스트 검색, offset을 랜덤으로 설정
        const randomOffset = Math.floor(Math.random() * 950); // 0부터 950 사이의 랜덤 값 (50개씩 가져올 경우)

        fetch(`https://api.spotify.com/v1/search?q=lofi%20chillhop&type=playlist&limit=50&offset=${'${randomOffset}'}`, {
            method: 'GET',
            headers: {
                'Authorization': 'Bearer ' + accessToken
            }
        })
            .then(response => {
                console.log('Response received: ', response.status);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}, message: ${response.statusText}`);
                }
                return response.json();
            })
            .then(data => {
                console.log('Playlists: ', data); // 전체 플레이리스트 데이터를 출력

                if (data.playlists && data.playlists.items) {
                    const playlists = data.playlists.items;

                    // 플레이리스트가 없을 때
                    if (playlists.length === 0) {
                        document.getElementById('playlist-list').innerHTML = "<p>관련 플레이리스트가 없습니다.</p>";
                        return;
                    }

                    let playlistListHTML = '';  // HTML을 저장할 변수

                    playlists.forEach(playlist => {
                        let playlistName = playlist.name ? playlist.name : "Unknown Playlist";
                        let playlistId = playlist.id ? playlist.id : "Invalid ID";

                        // 이미지가 있는지 확인하고, 없다면 기본 이미지 사용
                        let playlistImage = (playlist.images && playlist.images.length > 0) ? playlist.images[0].url : 'https://via.placeholder.com/150'; // 기본 이미지 URL

                        playlistListHTML += `
                            <div class="playlist-card animate__animated animate__fadeInUp slide">
                                <div style="position: relative; width: 100%; height: 150px;">
                                    <img src="${'${playlistImage}'}" alt="${'${playlistName}'}" style="width: 100%; height: 100%; object-fit: cover;" onclick="playPlaylist('${'${playlistId}'}')">
                                    <button class="play-button" onclick="playPlaylist('${'${playlistId}'}')">
                                        ▶
                                    </button>
                                </div>
                                <p><strong>${'${playlistName}'}</strong></p>
                            </div>
                            `;
                    });

                    document.getElementById('playlist-list').innerHTML = playlistListHTML;

                } else {
                    console.error('No playlists found in the API response.');
                    document.getElementById('playlist-list').innerHTML = "<p>No playlists found</p>";
                }
            })
            .catch(error => {
                console.error('Error fetching playlists:', error);
                document.getElementById('playlist-list').innerHTML = "<p>플레이리스트를 불러오는 도중 오류가 발생했습니다.</p>";
            });
    }

내 개인 프로젝트 이런 코드에 구사해도 재밌겠다는 생각을 했는데, 강사님이 굳이라고 하셔서 재밌다는 생각이 사라졌다,,

스프링에 구사하면 페이지가 느려질 가능성이 있다고 하셨다.

갑자기 팍 식네

여하튼 리액트는 저런 식으로 사용한다.

JS Filter

이름 그대로 필터링을 하는 코드다.

// 필터링할 배열
const num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 개발자가 직접 작성한 콜백 함수
function isEven(value) {
    return value % 2 === 0; // 짝수인 경우 true 반환
}

// 배열의 요소를 순회하면서 필터링된 배열로 반환
const result = num.filter(isEven);
console.log(result); // 출력: [2, 4, 6, 8, 10]

filter(조건);
이런식으로 필터링해서 결과값을 도출하는 함수이다. 위 예제 코드는 isEven을 사용해서 짝수만을 출력하게끔 홀수를 걸러준다. 더 간단히 말하면 참인 애들이 살아남는다고 생각하면 된다. isEven의 조건의 참은 짝수니까 짝수들이 살아남아서 콘솔에 출력되는 것.

그러니까 이름 그대로의 의미인 필터링하는 기능을 갖는다!

filter의 장점은 원본을 살려놓고 데이터를 가공할 수 있음에 있다. 그러니까 리액트에서 중요한 불변성을 유지하면서 데이터를 가공할 수 있다.

간단한 또 다른 예제를 참고하면

console.clear();

console.log("==원본==");
const arr = [10, 20, 30, 40, 50];
console.log(arr);

console.log("==filter 적용==");
// const afterFilter = arr.filter((el, index) => {
//   return index != 2;
// });

// const afterFilter = arr.filter((el, index) => index != 2);

// const afterFilter = arr.filter((el, index) => {
//   return true;
// });

const afterFilter = arr.filter((el, index) => {
  return el != 40;
});

console.log(afterFilter);

console.log(arr);

결과값은.

이렇게 나온다.

아까 말한대로 참인 것만 살아남으니까 40이 배열에서 제거된 모습이고, 또한 불변성을 유지하기에 arr를 다시 콘솔에 찍으면 원본 배열은 그대로 유지되어있는 모습.

이제 이걸 아까 그 맨 위의 코드에 적용시켜보면 이제 약간 심화?일듯.

저 코드에서 기록했을 때, 요소 하나를 지우는 것을 만들어보는 것이다.

우선 filter를 추가한 코드를 보자!

console.clear();

import React, { useState } from "https://cdn.skypack.dev/react@18";
import ReactDOM from "https://cdn.skypack.dev/react-dom@18";

const App = () => {
    const [number, setNumber] = useState(0);
    const [recordNums, setRecordNums] = useState([10, 20, 30]);

    const saveRecord = () => {
        setNumber(0);
        setRecordNums([...recordNums, number]);
    };

    const clearNumbers = () => {
        setRecordNums([]);
    };

    // const removeNumber = (index) => {
    //     setRecordNums(recordNums.filter((_, _index) => {
    //         return _index != index
    //     }));
    // };

    const removeNumber = (index) => {
        setRecordNums(recordNums.filter((_, _index) => _index != index));
    };

    return (
        <>
            <div>숫자 : {number}</div>
            {recordNums.length == 0 ? (
                <div>기록 없음</div>
            ) : (
                <>
                    <h3>기록</h3>
                    <ul>
                        {recordNums.map((recordNum, index) => (
                            <li key={index}>
                                <span>
                                    {index + 1}번 : {recordNum}
                                </span>
                                &nbsp;
                                <button onClick={() => removeNumber(index)}>삭제</button>
                            </li>
                        ))}
                    </ul>
                </>
            )}

            <div>
                <button
                    onClick={() => {
                        setNumber(number + 1);
                    }}
                >
                    증가
                </button>
                &nbsp;
                <button
                    onClick={() => {
                        setNumber(number - 1);
                    }}
                >
                    감소
                </button>
                &nbsp;
                <button onClick={saveRecord}>기록</button>
                &nbsp;
                <button onClick={clearNumbers}>전체기록삭제</button>
            </div>
        </>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));

여기서 핵심은 이거다.

    const removeNumber = (index) => {
        setRecordNums(recordNums.filter((_, _index) => _index != index));
    };

<button onClick={() => removeNumber(index)}>삭제</button>

<button onClick={() => removeNumber(index)}>삭제</button> 여기서 index를 매개변수로 함수에 전송

const removeNumber = (index) => { 여기서 index를 매개변수로 받아서

setRecordNums(recordNums.filter((_, _index) => _index != index));여기서 값을 대조하고 해당 값을 제외하고 다시 배열을 덮어쓴다.

그럼 delete를 쓰면 되지 왜 filter를 쓰느냐? 아까도 말 했지만 리액트의 불변성 규칙을 따르기 위함이다.

코드를 직접 실행한 결과는 이거다. (직접해봐라!)

'Coding History' 카테고리의 다른 글

JS 리액트 TODO LIST  (2) 2024.09.26
리액트 (템플릿 리터럴, 컴포넌트 리팩토링, onChange)  (1) 2024.09.24
chat 웹앱 수업.  (0) 2024.09.11
VO, DTO, Entity의 차이점  (0) 2024.09.09
OAuto2 가 무엇인가?  (1) 2024.09.03