실무에서는 for문 보다는 map과 filter
를 더 많이 사용하게 된다.
map과 filter모두 배열의 내장함수 이기때문에 사용할 때는 배열과 함께 사용해야 한다.
map은 배열의 원소를 일괄적으로 변형시킬 때 사용하기 좋다.
const classmate = ["철수","영희","훈이"]
classmate.map((item)=>(item+"어린이"))
=> (3)["철수어린이","영희어린이","훈이어린이"] 로 출력된다.
map안에서 사용되는 item은 classmate의 원소들이 들어갈 파라미터(매개변수) 입니다.
파라미터의 네이밍은 아무거나 적어도 관련없음
객체가 원소인 배열에서도 map을 이용해 객체를 가공해보자.
const classmate = [
{name: "철수"},
{name: "영희"},
{name: "훈이"}]
//item.name => "철수","영희","훈이"
//school 속성을 일괄적으로 추가하기.
classmate.map((item)=>({name : item.name + "어린이", school : "떡잎유치원"}))
=> (3)[
{name : "철수어린이",school : "떡잎유치원"},
{name : "영희어린이",school : "떡잎유치원"},
{name : "훈이어린이",school : "떡잎유치원"}
]
❗️화살표 함수 () ⇒ {} vs () ⇒ ()
→ 소괄호 ()로 감싸진 부분이 return 됩니다.(return문을 작성하지 않아도 리턴 된다.)
반면 중괄호{}로 감싸진 함수는 return문이 없다면 반환값이 없다.
프로젝트에서는 컴포넌트의 리턴값 안에서 많이 사용하게 된다.
map을 리턴값 안에서 사용하기위해 {}으로 감싸서 사용한다.
(return 안에 자바스크립트를 가지고 오기 위해서 {}을 사용하는 것이다.)
// RenderMap 컴포넌트
const RenderMap = ()=>{
const classmate = ["철수","영희","훈이"]
return(
//중괄호를 이용해 자바스크립트를 컴포넌트의 return값 안으로 데리고 들어온 것 입니다.
//리턴되어야 할 값이 한줄이기때문에 괄호생략이 가능합니다.
{classmate.map( (item)=> <div>{item}어린이</div> )}
)
}
export default RenderMap
filter는 이름 그대로 배열의 원소를 필터링 해주는 메서드.
filter는 필터링 할 조건으로 객체 혹은 배열의 각 원소를 검사하여 그 조건에 맞는 원소들만 결과값으로 도출한다.
const num = [1,2,3,4,5,6,7,8,9,10]
num.filter((item)=>(item<=8))
=> (8) [1, 2, 3, 4, 5, 6, 7, 8]
filter 안에서 사용되는 item 역시 배열의 원소가 들어갈 파라미터다.
refetchQuery는 기존에 받아왔던 데이터가 변경 되었을 경우 최신 데이터로 다시 fetch 해주기 위해 사용된다.
예를들어 게시글을 삭제하는 api인 deleteBoard 같은 경우를 생각해보자.
만일, 게시글을 하나 삭제하였다면 삭제된 1개의 게시글은 그 즉시 우리 눈 앞에서는 사라져야 할 것이다.
하지만 refetch를 추가적으로 하지 않는다면 브라우저를 새로고침 하지 않는한 DB에서 게시글 삭제는 처리됐어도 브라우저는 새로고침 하지 않으면 반영되지 않는다.
// 삭제 Mutation
const deleteBoard = async () => {
try {
const result = await deleteBoard({
variables: {
boardId: event.target.id,
},
});
} catch (error) {
console.log(error);
}
};
위의 코드는 흔하게 볼 수 있는 삭제 Mutation이다.
위 코드는 삭제 Mutation이 실행 된 후에는 데이터가 변경 되었을 테지만 아직 최신 데이터가 반영 되지 않았다.
따라서 refetchQueries를 이용해 최신 데이터로 다시 받아오면.
//refetchQueries를 이용해 최신 데이터 받아오기
const deleteBoard = async () => {
try {
const result = await deleteBoard({
variables: {
boardId: event.target.id,
},
refetchQueries: [ // 리페치 하는 부분
{
query: FETCH_BOARDS // FetchBoard 를 한번 더 실행해줌
},
]
});
} catch (error) {
console.log(error);
}
};
위의 코드 useMutation 함수 안에서 refetchQueries라는 키가 있다는 것을 알 수 있다.
refetchQueries는 Apollo에서 제공하는 기본 기능이다.
refetchQueries는 배열로 시작하여, 그 안에 어떤 query를 하고, 그 query의 variables가 무엇인지 다시 설정해주면 Mutation이 성공적으로 끝났을 경우 refetchQueries를 실행해준다.
💡refetchQueries에서의 variables
→ 기존의 fetch 부분에서 보내준 variables가 없다면 따로 적지 않아도 되지만, 만일 보내준 variables가 있다면 refetchQuerise부분을 아래와 같이 적어주어야 한다.refetchQueries: [{ query : FETCH_BOARDS, variables : { 기존의 fetch때 보내준 것} }]
(모든 Mutation 이후에 refetchQueries를 사용하는 것은 아니다. Mutation 이후 변경된 데이터를 받아올 수 없을 경우에 사용한다.)
예제
import { Test } from '../../src/test2';
export default function Test2() {
const List = ['사과', '딸기', '바나나'];
return (
<>
{List.map((data) => (
<Test>{data}</Test>
))}
</>
);
}
위의 예시처럼 map을 사용할때, 우리가 알던 대로라면 Test 컴포넌트에 사과, 딸기, 바나나가 순서대로 브라우저에서 보여줘야 할 것이다. 하지만 console 창에서는 Warning과 1줄이 출력된다.
key값을 부여하지 않았을 경우 오류가 발생하는 것을 확인할 수 있다.
왜 map에서 key를 사용해야 하는걸까?
해당 경고는 React가 어떤 요소를 변경, 추가, 삭제할지 식별하기 위함이다.
key가 없는 경우에는 가상 DOM을 비교하는 과정에서 순차적으로 비교하며 변화를 감지한다.
만일, key가 있다면, 이 값을 사용하여 어떤 것이 수정이 됐는지 빠르게 감지할 수 있다.
(이 부분은 react가 브라우저에 그려지는 과정, 가상 DOM에 대해 공부하면 더 빠르게 이해할 수 있다. DOM에 대해 공부하자)
위의 설명을 짧게 보충한다면, React에서는 기존 데이터와 바뀐 데이터를 비교하여 바뀐 부분을 화면에 그려준다.
여기서 비교할 때 고유한 Key값이 없다면 모든 데이터를 비교해야 하지만, Key가 있으면 Key값만 비교하여 Key가 추가 됐는지, 삭제 됐는지만 비교하여 불필요한 비교나 렌더링을 없애준다.
그러기 위해 key는 안정적인 고유성을 부여하기 위해 중복되는 값이 아닌 것으로 지정해줘야 한다. (만약 key를 지정하지 않을 경우 자동으로 index를 키로 사용합니다. 하지만 이는 좋은 방법이 아니라 경고가 뜨게된다.)
그래서 React 공식 문서에서도 Key 값으로 id를 주는 것을 추천하고 있다.
import { Test } from '../../src/test2';
export default function Test2() {
const List = ['사과', '딸기', '바나나'];
return (
<>
{List.map((data) => (
<Test key={id}>{data}</Test>
))}
</>
);
}
앞으로 효율적인 React를 위해 map을 사용할 때는 꼭 id값을 적어주자.
index를 key로 줘도 괜찮은 상황이 있다. 아래 3가지 조건을 만족하면 가능하다.
1. 정적인 데이터. 계산되지 않고 변경되지 않는 데이터
2. map에 있는 모든 데이터에 id가 없을 경우
3. 데이터가 재정렬되거나 필터링 되지 않는 경우. (계속 그 자리 그대로)
위의 3가지를 만족한다면 index를 key로 사용해도 안전하다.
하지만 서버에서 받아오는 데이터라면 그럴리가 없다는 것인데 때문에 Index를 Key로 두는 경우는 거의 없다고 봐야 한다.