TIL-1/18
map

element 부분에 철수, 영희, 훈이가 들어가고 map 함수가 배열을 순회하면서 어린이를 붙여 반환한다.

결과값

또한 배열안에 객체도 활용할 수 있다.
새로운 배열을 다시 리턴한다.

또한 배열안의 객체의 데이터를 추가할 수도 있다. 참고로 데이터를 변경할 때는 배열안의 갯수는 처음과 같아야한다.

또한 el 안의 괄호도 모두 생략 가능하다. 왜냐하면 화살표 함수이기 때문이다. 화살표 함수가 뭔데?

이러한 특징 때문에 ()를 생략할 수 있다.
그러나 배열의 요소가 객체로 되어있으면 ()생략이 불가능하다.
생략하게 되면 객체의 중괄호가 화살표함수의 중괄호로 되어버리기 때문이다.
filter

최대 배열의 갯수보다 같거나 작은 갯수가 반환된다.

이런식으로 배열안에 객체도 걸러줄 수 있다.
또한 map, filter를 둘 다 사용할 수도 있다.

refetchQueries
말그대로query를 다시fetch한다는 것이다.
refetchQueries를 사용하는 경우는 useMutation을 한 후, 기존에 받아왔던 query의 data가 변경되었을 경우 사용하게된다.
예를 들어, query로 받아온 데이터가 10개 인데 Mutation을 통해 하나를 삭제했다면, 데이터는 9개가 되므로 다시 query를 통해 서버에서 9개 짜리의 데이터를 받아와야한다.
예제코드
const deleteBoard = async () => {
try {
const result = await deleteBoard({
variables: {
boardId: router.query.boardId,
},
});
} catch (error) {
console.log(error);
}
};
삭제 기능의 Mutation이다.
삭제 후의 기존 query로 받아온 데이터에 삭제된 데이터가 반영되게 하기위해 refetchQueries를 이용한다.
const deleteBoard = async () => {
try {
const result = await deleteBoard({
variables: {
boardId: router.query.boardId,
},
refetchQueries: [
{
query: FETCH_BOARDS,
variables: { boardId: router.query.boardId },
},
],
});
} catch (error) {
console.log(error);
}
};
useMutation 함수 안에서 refetchQueries라는 키가 있다. 이건 Apollo에서 제공하는 기본 기능이다.
refetchQueries는배열로시작하며, 그 안에 어떤 query를 하고, 그 query의 variables가 무엇인지 다시 설정해주면, Mutation이 성공적으로 끝났을 경우, refetchQueries를 실행시켜준다.
map의 index를 key로 사용시 발생하는 문제점
예제코드
import { Test } from '../../src/test2';
export default function Test2() {
const List = ['사과', '딸기', '바나나'];
return (
<>
{List.map((data) => (
<Test>{data}</Test>
))}
</>
);
}
console.log() 에 문제가 발견될 것이다.

각 child는 unique한key가 있어야 한다고 나와있다.
왜 이런 메세지가 뜨는 걸까???
React에서 key가 필요한 이유
해당 경고는 React가 어떤 요소를 변경, 추가, 삭제할지 식별하기 위함이다. key가 없는 경우에는 가상DOM을 비교하는 과정에서 순차적으로 비교하여 변화를 감지한다. key가 있다면, 이 값을 사용하여 어떤 것이 수정되었는지 빠르게 찾을 수 있다.
간단히 설명하면, React에서는 기존 데이터와 바뀐 데이터를 비교하여 바뀐 부분을 화면에 그려준다.
여기서 비교할 고유한key값이 없다면, 모든 데이터를 비교해야 하지만, key가 있으면 key값만 비교하여 불필요한 비교나 렌더링을 없애준다..!
그러기 위해서는 key는 안정적인 고유성을 부여하기 위해 중복되는 값이 아닌 것으로 지정해주어야한다.
만약 key를 지정하지않을경우 자동으로 index를 키로 사용한다. 하지만 이는 좋은 방법이 아니라고 경고가 뜨는 것이다.
그래서 React 공식 문서에서도 key값으로 id를 주는 것을 추천한다.
예제이기 때문에 id가 없지만 예시로 넣었다.
import { Test } from '../../src/test2';
export default function Test2() {
const List = ['사과', '딸기', '바나나'];
return (
<>
{List.map((data) => (
<Test key={id}>{data}</Test>
))}
</>
);
}
Index를 key로 줘도 괜찮은 상황
1. 정적인 데이터. 계산되지 않고 변경되지 않는 데이터
2. map에 있는 모든 데이터에 id가 없을 경우
3. 데이터가 재정렬되거나 필터링되지 않는 경우
위의 3가지를 모두 만족한다면 사용해도 안전하다. 하지만 서버에서 받아오는 데이터면 그럴일은 없겠쥬??
오늘한 실습코드
// 07-01-map-fruits/index.js
const FRUITS = [
{ number: 1, title: "레드향" },
{ number: 2, title: "샤인머스켓" },
{ number: 3, title: "산청딸기" },
{ number: 4, title: "한라봉" },
{ number: 5, title: "사과" },
{ number: 6, title: "애플망고" },
{ number: 7, title: "딸기" },
{ number: 8, title: "천혜향" },
{ number: 9, title: "과일선물세트" },
{ number: 10, title: "귤" },
]; //다시 렌더링할 필요가 없는 것들은 위에다 올려놓는다. 하드코딩같은것들.
export default function MapFruitsPage() {
// const aaa = [
// <div>1 레드향</div>,
// <div>2 샤인머스켓</div>,
// <div>3 산청딸기</div>,
// ];
// const bbb = ["나의레드향", "나의샤인머스켓", "니의산청딸기"].map((el) => (
// <div>{el}</div>
// ));
const ccc = FRUITS.map((el) => <div>{`${el.number} ${el.title}`}</div>);
return (
<>
<div>{ccc}</div>
<div>
{FRUITS.map((el) => (
<div>{`${el.number} ${el.title}`}</div> //이렇게 직접 넣는 것이 코드의 가독성이 좋다 코드가 길어지면 ccc가 의미하는 것을 바로 알기 쉽지않기 때문이다.
))}
</div>
</>
);
}
// 07-02-map-checkbox/index.js
import { gql, useQuery } from "@apollo/client";
import styled from "@emotion/styled";
const FETCH_BOARDS = gql`
query fetchBoards {
fetchBoards {
number
writer
title
createdAt
}
}
`;
const Column = styled.div`
width: 20%;
`;
const Row = styled.div`
display: flex;
`;
export default function MapCheckboxPage() {
//const { data: 원하는변수명 } = useQuery() data 변수 이름변경 가능!!
const { data } = useQuery(FETCH_BOARDS);
return (
<div>
{data?.fetchBoards.map((el) => (
<Row>
<Column>
<input type="checkbox" />
</Column>
<Column>{el.number}</Column>
<Column>{el.title}</Column>
<Column>{el.writer}</Column>
<Column>{el.createdAt}</Column>
</Row>
))}
</div>
);
}
// 07-03-map-checkbox-delete/index.js
import { gql, useMutation, useQuery } from "@apollo/client";
import styled from "@emotion/styled";
const FETCH_BOARDS = gql`
query fetchBoards {
fetchBoards {
number
writer
title
createdAt
}
}
`;
const DELETE_BOARD = gql`
mutation deleteBoard($number: Int) {
deleteBoard(number: $number) {
message
}
}
`;
const Column = styled.div`
width: 20%;
`;
const Row = styled.div`
display: flex;
`;
export default function MapCheckboxDeletePage() {
//const { data: 변경가능 } = useQuery() data 변수 이름변경 가능!!
const { data } = useQuery(FETCH_BOARDS);
const [deleteBoard] = useMutation(DELETE_BOARD);
const onClickDelete = (event) => {
deleteBoard({
variables: {
number: Number(event.target.id),
}, //html 에서 받아온거기 때문에 넘버타입으로 변환.
refetchQueries: [{ query: FETCH_BOARDS }], //만약 FETCH_BOARDS에 variables가 들어있었다먄 , 하고 넣어줘야한다. 리패치를 해야지 삭제를하면 새로고침필요없이 바로 삭제된게보임
});
event.target.id; // === number 왜냐 버튼에 id=넣었으니까
}; //js는 map함수에서 반복된 것들을 기억해 두려고 하기 때문에, 고유한 값을 사용해주면 체크박스 부분이 사라진다. 하지 않으면 체크박스는 남아있다.
return (
<div>
{data?.fetchBoards.map((el) => (
<Row key={el.number}>
<Column>
<input type="checkbox" />
</Column>
<Column>{el.number}</Column>
<Column>{el.title}</Column>
<Column>{el.writer}</Column>
<Column>{el.createdAt}</Column>
<Column>
<button id={el.number} onClick={onClickDelete}>
삭제
</button>
</Column>
</Row>
))}
</div>
);
}
Author And Source
이 문제에 관하여(TIL-1/18), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@olzlel2000/TIL-118저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)