끙차끙차...
6장. 컴포넌트 반복
웹 애플리케이션을 만들다 보면, 반복되는 내용을 보여주는 순간이 종종 생긴다.
이때마다 복사 붙여넣기를 사용하는 건... 코드 양도 늘어나고, 비효율적이며, 관리가 제대로 될 리도 없다!
따라서 반복적인 내용을 효율적으로 보여주고 관리하는 법을 익혀볼 예정.
6-1) JS의 map() 함수
얼마 전 배웠던 map() 함수!
→ 파라미터로 전달된 함수를 사용해서 배열 내 각 요소를 원하는 규칙에 따라 변환한 후, 새로운 배열을 return 한다.
1. 문법
arr.map(callback, [thisArg])
요 녀석의 파라미터는 다음과 같다!
- callback : 새로운 배열이 요소를 생성하는 함수
→ currentValue : 현재 처리하고 있는 요소
→ index : 현재 처리하고 있는 요소의 index 값
→ array : 현재 처리하고 있는 원본 배열
- thisArg(선택) : callback 함수 내부에서 사용할 this 래퍼런스
2. 예제
이런 식으로!
얘를 다시 ES6 문법으로 작성해보면...!
따라란. (확실히 코드가 간단해지기는 한다! 화살표 만만세)
6-2) 데이터 배열을 컴포넌트 배열로 변환하기
앞서 했던 것과 똑같은 원리로, 기존 배열을 통해 컴포넌트로 구성된 배열을 생성할 수도 있다.
1. 컴포넌트 생성하기
일단 새로운 파일을 하나 생성해주자.
src/InterationSample.js
우선 문자열로 구성된 배열을 하나 선언(name) 한 후,
그 배열 값을 사용해 JSX 코드로 된 배열(<li> ... </li>)을 새로 생성해 nameList에 담아줬다.
요 녀석을 App.js에 불러와 렌더링 해보면...
으엥. 개발자 도구에서 error를 표시하고 만다.
key라는 녀석이 필요하다는데... 얘는 또 뭐람?
6-3) key
React에서 key는 컴포넌트 배열을 랜더링 했을 때 어떤 원소에 변동이 있었는지 알아내려고 사용한다.
유동적인 데이터를 다룰 경우 원소를 새로 생성할 수도, 제거할 수도, 수정할 수도 있다!
즉 key가 없을 때는 Virtual Dom을 비교하는 과정에서 리스트를 순서대로 비교하지만,
key가 있으면 이 값을 이용해 어떤 변화가 일어났는지 더욱 빠르게 알아낼 수 있는 것!
1. key 설정
key 값을 설정할 때는 map 함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯 설정하면 된다.
??? 당최 무슨 소리?
InterationSample.js
아하! props를 설정하듯 key 값으로 데이터의 고윳값을 정해주면 된다.
하지만 우리가 만든 컴포넌트에는 데이터별 고유 번호가 존재하지 않는디?
→ 이 경우 map 함수에 전달되는 콜백 함수의 인수인 index 값을 사용하면 된다.
단, index를 key로 사용하면 배열이 변경될 때 효과적으로 리렌더링하지 못하므로 고유의 값이 없을 때만 이용한다!
6-4) 응용
이를 통해 동적인 배열을 렌더링 하는 걸 구현해보자.
또한 index를 key로 사용하면 비효율적이니, 이러한 상황에는 어떻게 고윳값을 만들 수 있을지도!
전체 흐름 ↓
초기 상태 설정 → 데이터 추가 기능 구현 → 데이터 제거 기능 구현
1. 초기 상태 설정하기
InterationSample 컴포넌트에서 useState를 이용해 상태를 설정해주자!
InterationSample.js
총 세 가지 상태를 사용했다.
첫째는 데이터 배열,
둘째는 텍스트를 입력할 수 있는 input의 상태,
셋째는 새로운 항목을 추가할 때 사용할 고유 id를 위한 상태!
이번에는 map 함수를 사용할 때 key 값을 index 대신 name.id로 지정해줬다.
역시 결과는 똑같다!
2. 데이터 추가 기능 구현하기
새로운 이름을 등록할 수 있는 기능을 구현해보자.
우선 input과 button을 렌더링 하고, input의 상태를 관리!
InterationSample.js
앞서 했던 것처럼 input에 입력된 값을 onChange 이벤트 발생 시 받아온다!
그 후 버튼을 클릭했을 때 호출할 onClick 함수를 선언! 버튼의 onClick 이벤트로 설정해준다.
작성해준 onClick 함수는 concat 함수를 이용해 새로운 항목을 추가한 배열을 만들고,
setNames를 통해 상태를 업데이트!
이때 배열에 새 항목을 추가하는 push 대신 concat을 사용한 이유는?
→ push는 기존 배열 자체를 변경, concat은 새로운 배열을 만들기 때문!
기존 배열 자체가 변경된 것 아닌가?
→ React에서 상태를 업데이트할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야 한단다.
- 이를 불변성 유지라고 하며, 그래야 이후 React 컴포넌트 성능을 최적화할 수 있다.
아무튼 onClick 함수를 통해 새로운 항목을 추가할 때
객체의 id 값은 nextId를(클릭될 때마다 1씩 증가), 기존 input 내용은 비워지도록 만들었다!
추가도 잘 작동하는 모습! 참말로 신기할 다름이다.
3. 데이터 제거 기능 구현하기
각 항목을 더블클릭하면 해당 항목을 삭제하도록 해보자.
물론 이 때도 불변성을 유지해줘야 한다 → filter 함수를 사용!
잠깐 filter를 짚고 넘어가자면...
filter 함수의 인자에 분류하고 싶은 조건을 반환하는 함수를 넣어주면 쉽게 분류할 수 있다!
InterationSample.js
다음과 같은 코드를 추가!
우선 onRemove 함수는 filter를 이용해, names 항목 중 전달받은 name.id가 아닌 녀석들만 남긴 배열을 반환!
이를 다시 setNames에 넣어줌으로써 새로운 배열을 렌더링 한다.
기존 name.text를 띄워주던 li에 onDoubleClick 이벤트를 연결!
더블클릭 시 onRemove 함수에 해당 항목의 id를 전달!
역시 잘 지워지는 것을 볼 수 있다. 세상에 마상에.
흐아... 점점 복잡해진다!
아무튼 컴포넌트 배열을 렌더링 할 때는 key 값 설정에 항상 주의해야 하며,
상태 안에서 배열을 변형할 때는 배열에 직접 접근하는 것이 아니라 concat / filter 등을 사용해야 함을 기억하자.
이러한 배열 내장 함수를 사용하여, 새로운 배열을 만든 후, 다시 이를 새로운 상태로 설정해주도록!
'source-code > React' 카테고리의 다른 글
리액트를 다루는 기술 _ 9장 (0) | 2021.03.11 |
---|---|
리액트를 다루는 기술 _ 8장 (0) | 2021.03.10 |
리액트를 다루는 기술 _ 5장 (0) | 2021.03.09 |
리액트를 다루는 기술 _ 4장 (0) | 2021.03.09 |
리액트를 다루는 기술 _ 1장, 2장, 3장 (1) | 2021.03.09 |