[리액트공부] 6. 컴포넌트 반복

kkado·2022년 7월 30일
0

리다기

목록 보기
7/16
post-thumbnail

배열과 map() 함수

자바스크립트 배열 객체의 내장 함수인 map 함수를 사용하여, 반복되는 컴포넌트를 렌더링할 수 있다.

map 함수는 파라미터로 전달된 함수를 사용해서 배열 내의 각 요소를 규칙에 따라 변환한 후, 그 결과로 새로운 배열을 생성할 수 있다.

map 함수 문법

arr.map(callback, [thisArg])

  • callback : 새로운 배열의 요소를 생성하는 함수. 파라미터는 다음과 같다.
    • currentValue : 현재 처리하고 있는 요소
    • index : 현재 처리하고 있는 요소의 배열 내 index 값
    • array : 현재 처리하고 있는 원본 배열
  • thisArg(선택) : callback 함수 내에서 사용할 this 레퍼런스


간단하게 사용해 본 모습. 배열 내의 요소들을 각각 item으로 전달받을 수 있다.


두 번째 파라미터는 index를 갖고 있다.

map을 이용해 렌더링하기

export default function IterationSample() {
    const names = ["눈사람", "얼음", "눈", "바람"];
    const nameList = names.map(item => <li>{item}</li>);

  return <ul>{nameList}</ul>;
}

names 리스트를 만들고, 각각의 요소에 대해서 <li> 태그로 감싼 리스트를 <ul> 태그 안에 넣어서 리턴한다.

그럼 잘 나오게 되지만, 콘솔 창을 열어보면 에러가 뜬다.

모든 리스트의 자식들은 각각의 unique한 key 값을 가져야 한다고 한다.

key

리액트에서 key는 컴포넌트 배열을 렌더링했을 때 어떤 원소에 변화가 있었는지 알아내기 위해 사용한다.

key 값이 없다면, 리스트를 순차적으로 비교해 가면서 변화를 감지하여야 하지만, key 값이 있다면 어디서 변화가 일어났는지 빠르게 알아낼 수 있다.

key 값은 언제나 유일해야 한다. 따라서 데이터가 가진 고유한 값을 key 값으로 설정한다.

하지만 별다른 유일한 값 없이, 위의 예제처럼 ["눈사람", "얼음", "눈", "바람"] 와 같은 단순한 리스트라면 어떡할까? 앞서 살펴보았지만, 리스트 내에서 각각의 요소들이 가지는 index 값은 0, 1, 2... 이므로 unique하다고 할 수 있다. 즉 우리는 index 값을 key 값으로 사용할 수 있다.

export default function IterationSample() {
  const names = ["눈사람", "얼음", "눈", "바람"];
  const nameList = names.map((item, index) => <li key={index}>{item}</li>);

  return <ul>{nameList}</ul>;
}

li 태그 안에 key 값으로 index를 넣어 주면 오류가 해결된다.

하지만, 고유한 값이 없을 때만 index를 사용해야 한다. 배열의 인덱스를 key 값으로 사용하면 배열이 변경될 때 효과적으로 리렌더링 하는 데에 어려움이 있기 때문이다.

아니면, 리스트를 생성할 때
[{id: 1, text: '눈사람}, {id: 2, text: '얼음'}...] 과 같이, id 값을 지정해 주어서 생성하는 방법 또한 물론 가능하다.

리스트 추가하는 기능 구현

export default function IterationSample() {
  const [names, setNames] = useState([
    { id: 1, text: "눈사람" },
    { id: 2, text: "눈" },
    { id: 3, text: "얼음" },
  ]);
  const [inputText, setInputText] = useState("");
  const [nextId, setNextId] = useState(names.length + 1);

  const onChange = (e) => {
    setInputText(e.target.value);
  };

  const onClick = () => {
    setNames([...names, {id: nextId, text: inputText}]);
    setNextId((curr) => curr + 1);
    setInputText("");
  };

  const nameList = names.map((item) => <li key={item.id}>{item.text}</li>);

  return (
    <>
      <input

        type="text"
        placeholder="Input something"
        onChange={onChange}
        value={inputText}
      />
      <button onClick={onClick}>추가</button>
      <ul>{nameList}</ul>
    </>
  );
}

이전에 투두리스트 만들 때 해봐서 쉽게 만들 수 있었다.
중요한 부분은 setNames([...names, {id: nextId, text: inputText}]); 인데 여기서 ...names 라고 해주면 기존의 names 리스트에 있던 원소들을 그대로 가져와준다. 즉 기존의 names 리스트 뒤에 새로 nextId와 inputText를 이어붙이는 기능을 한다.

그냥 names라고 하게 되면 [[(names)], (새 리스트)] 이런 식으로 서로 떨어져 버린다.

잘 추가가 되고 있다.

리스트 제거 기능 구현

리스트의 각 항목을 더블클릭 했을 때, 그 항목이 화면에서 사라지는 기능을 구현해 보자.

불변성을 유지하면서, 특정 항목을 지우고자 할 때는 filter 기능을 사용한다.
filter 함수는 배열에서 특정 조건을 만족하는 원소들만 쉽게 분류할 수 있다.

3이 아닌 원소들만 리스트에 남아 있는 모습을 볼 수 있다.

  const deleteList = (id) => {
    setNames(names.filter((item) => item.id !== id));
  };

  const nameList = names.map((item) => (
    <li key={item.id} onDoubleClick={() => deleteList(item.id)}>
      {item.text}
    </li>
  ));

제거하는 함수에 제거할 원소의 id값을 넘겨주고, names 리스트에서 그 id값이 아닌 원소들만 남긴 새 리스트로 setNames 해준다.


정리

map 함수를 이용해서 반복적으로 데이터를 렌더링할 수 있다. 다만 이 과정에서 unique한 key 값을 지정해 주어야 한다.

...filter 기능을 이용해서 리스트를 변형할 수 있다.

profile
울면안돼 쫄면안돼 냉면됩니다

0개의 댓글