이거 상당히 재밌는 것 같다. (여담)
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>
<button
onClick={() => {
setNumber(number - 1);
}}
>
감소
</button>
<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>
<button onClick={() => removeNumber(index)}>삭제</button>
</li>
))}
</ul>
</>
)}
<div>
<button
onClick={() => {
setNumber(number + 1);
}}
>
증가
</button>
<button
onClick={() => {
setNumber(number - 1);
}}
>
감소
</button>
<button onClick={saveRecord}>기록</button>
<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 |