항해에서 프로젝트를 진행하면서 map과 filter를 자주 사용했는데, 간간히 TypeError: x.map is not a function
이라는 에러가 자주 떴었다.
굉장히 자주 본 에러라서 이제는 익숙한... .map()
을 배열 (array)가 아닌 경우에 대입했기 때문이었다.
같은 에러를 자주 본 이유는 내가 아직 배열을 다루는게 많이 미숙하다고 생각되어 다시한번 배열에 자주 쓰이는 map
과 filter
를 알아보고 덤으로 find
도 살짝 알아보려고 한다.
map()
메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환합니다.const arr1 = [1, 4, 9, 16];
// 1. 특정 숫자(값)을 갖고 있는 arr1배열이 있다고 했을 때,
const map1 = arr1.map(x => x * 2);
// 2. arr1 배열에 .map()을 사용하고 map함수의 콜백 함수로 "특정 값은 (해당 값*2)가 된다"라는 로직을 추가한다.
// 3. .map()을 돌린 arr1 배열을 새로운 상수인 map1에 할당한다.
console.log(map1);
// 4. 새로운 값이 할당된 map1을 콘솔에 찍으면 기존 arr1 배열에 있던 모든 요소들이 *2가 적용되어서 표시된다.
// 5. map1 = [2, 4, 18, 32]
arr1
에 있던 모든 요소들이 콜백 함수의 내용이 적용된 상태로 map1
이라는 새로운 배열이 만들어졌다.map()
은 보통 렌더링이 일어나고 변경된/변경되었을 값을 다시 list up 할 목적으로 사용했었다.rooms = [
{
id:1
roomName: aaa
member: [{memberId:1, nickname: qwer}]
}
]
// 1. rooms라는 배열이 있고, 해당 배열을 객체를 품고 있다.
{rooms.slice(0, 4).map((room) => {
// 2. rooms를 조건에 맞게 map을 돌리는데, slice를 이용해서 한번에 4개의 요소만 화면에 보이게 만든다.
// 3. map 이후 () 안에 들어있는 내용은 새로 반환하는 배열이고, 새 배열 안에 들어갈 요소가 어떤 요소인지 표시한다.
return (
// 4. 실 사용 시 해당 케이스에 map 함수는 rooms 배열 안에 있는 객체의 정보를 다르게 표시한 배열을 반환한다.
<div key={room.id}>
// 5. rooms 안에 있는 1개의 객체인 room은 고유 아이디가 있었기 때문에 해당 아이디를 반환할 수 있는 div를 지정한다.
<StTitle>{room.roomName}</StTitle>
// 6. room의 roomName을 반환하는 또 다른 styled div
<div>{room.member.length}/4</div>
// 7. 그리고 room에 있는 사람의 수를 표시하기 위해 room.member.length를 사용했다.
</div>
);
})}
// 8. rooms에 있는 객체들을 ui적으로 표시해서 객체들의 정보를 특정 형태로 변경해서 반환함.
filter()
메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환합니다.const arr2 = [12, 5, 8, 130, 44]
// 1. 특정 숫자(값)을 갖고 있는 arr1배열이 있다고 했을 때,
const filtered = arr2.filter(x => x >= 10);
// 2. filtered라는 상수에 arr2에 필터를 적용한 새로운 배열을 할당한다.
// 3. filtered 메소드의 콜백 함수로 "특정 값이 10보다 큰 경우"라는 로직을 추가한다.
console.log(filtered)
// 4. 새로운 값이 할당된 filtered를 콘솔에 찍으면 기존 arr2 배열에 있던 요소들 중 10보다 큰 요소들만 출력된다.
// 5. filtered = [12, 130, 44]
rooms = [
{
id:1
roomName: aaa
member: [{memberId:1, nickname: qwer}]
}
]
// 1. rooms라는 배열이 있고, 해당 배열을 객체를 품고 있다.
const deleteBtn = () => {
// 2. 삭제하기 버튼 클릭 시 함수가 실행되고,
const newRooms = rooms.filter((rooms) => room.id !== id)
// 3. 실행된 함수는 기존 rooms라는 배열에서 room의 id가 현재 room.id와 값이 다른 요소만 보아서 새로운 배열을 만든다.
// 4. 새롭게 만들어진 배열을 newRooms라는 상수에 넣고, 해당 상수를 setRooms에 업데이트 시킨다.
setRooms(newRooms)
}
// 5. 특정 아이디를 가진 요소를 제외한 요소들만 반환하기 때문에 삭제 기능이 구현된다.
find()
메서드는 주어진 판별 함수를 만족하는 첫 번째 요소의 값을 반환합니다. 그런 요소가 없다면 undefined를 반환합니다.const arr3 = [5, 12, 8, 130, 44];
// 1. 특정 숫자(값)을 갖고 있는 arr3라는 배열이 있다고 했을 때,
const found = arr3.find(element => element > 10);
// 2. arr3 배열에 .find()를 사용하고 해당 메소드의 콜백 함수로 "10보다 값이 큰 요소"라는 조건을 추가한다.
// 3. 콜백 함수 내부에 있는 조건을 만족한 요소 1개가 상수 found에 할당된다.
console.log(found);
// 4. find의 경우, 해당 조건에 맞는 요소를 찾자마다 해당 요소'만' 반환하게 된다.
// 5. 조건에 부합해도 그 이후에 나오는 요소들은 출력되지 않는다.
// 6. found = 12
function onClickSearchRoom() {
if (roomName.find((x) => x.includes(keyword.trim()))) {
// 1. 만약 roomName이 keyword에 있는 내용에서 공백을 제외한 경우를 포함한다면:
// 1-1. find 메소드의 매개변수로 includes를 사용해서 값을 포함한 모든 경우를 find에 걸리도록 했다.
alert('찾았닭');
dispatch(searchRoom(keyword));
// 2. keyword를 매개변수로 해서 searchRoom thunk함수를 실행한다.
// 3. 이때 keyword는 input에 입력되는 내용을 useState()를 이용해서 가져올 수 있다.
} else {
alert('찾는 방이 없닭');
}
setKeyword('');
}
백엔드에서 전달해주는 데이터는 객체를 가진 배열인 경우가 많이 때문에 배열을 수정하거나 건드리는 함수를 사용하게 된다.
초반에 map, filter에 대한 사용법을 자세히 알지 못 한채로 강의만 따라하다보니 확실히 실제로 내가 무언가를 만들 때 오류가 많이 발생했었다.
그래도 몇번 써보니 익숙해져서 TypeError는 뜨지 않지만, 다시 실수하지 않기 위해 정확히 내가 어떤 의도로 어떻게 썼는지 기록해둬야겠다! 아직 find는 실제로 내가 직접 써본건 아니니까 여기 적어둔 예시가 나중에 도움이 되면 좋겠다.