동적 렌더링 - 반복 렌더링
반복 렌더링 개념
반복 렌더링은 배열이나 리스트 형태의 데이터를 기반으로 여러 컴포넌트를 생성해 일관된 방식으로 화면에 출력하는 기법입니다.
반복 렌더링이란 갯수가 변할 수 있는 데이터를 동적으로 렌더링하는 것을 의미한다.
key 속성
JSX 속성으로 key를 사용하면 반복 렌더링으로 만들어진 컴포넌트를 개별적으로 구분할 수 있다.
key는 반드시 고유한 값을 가져야하며, 변하지 않는 값이 좋다.
예를 들어 배열의 index를 key로 사용할 수는 있지만, 배열의 크기에 따라 index가 변하므로 key로 사용하기에는 좋지 않다.
리액트는 가상 DOM을 비교(디핑)할 때 key를 보고 어떤 요소가 추가, 삭제, 혹은 수정되었는지 판단한다.
이 때 key가 없거나 index를 사용하면 배열의 순서가 바뀔 때 리액트가 모든 요소를 새로 그려버려 성능이 떨어지거나 상태(state)가 꼬이는 버그가 발생할 수 있다.
컴포넌트의 key 속성
컴포넌트도 배열로 렌더링 할 수 있다.
이 때도 마찬가지로 key속성을 사용하는데, key는 기본적으로 내부에서 props로 접근이 불가능하다는 점을 알아두자.
(내부에서 props로 접근이 불가능한 속성은 key 외에도 ref가 있다.)
import ListItem from './components/ListItem'
export default function App()
{
const arr = [ <ListItem key='1' text='item1'/>, <ListItem key='2' text='item2'/>, <ListItem key='3' text='item3'/> ];
return <>{ arr }</>
}
반복 렌더링 예시
배열을 사용
리액트에서 반복 렌더링을 사용하기 위해 JSX에 바로 문자열 배열을 출력하려 할 수 있다. 하지만 아무 전처리 없이 JSX에서 문자열 배열을 표시하면 배열의 값이 하나의 문자열로 모두 합쳐져서 표시된다.
export default function App()
{
const arr = [ 'item1', 'item2', 'item3' ];
return <>{ arr }</> // 'item1item2item3'`로 출력
}
따라서 배열의 요소를 각각의 태그로 출력하고 싶다면, 문자열 배열이 아닌 JSX 요소가 값으로 들어있는 배열을 사용해야한다.
export default function App()
{
const arr = [ <li key='1'>'item1'</li>, <li key='2'>'item2'</li>,<li key='3'>'item3'</li> ];
return <ul>{ arr }</ul>
}
위 코드를 렌더링하면 각 요소가 줄바꿈되어 다음과 같이 출력된다.
* item1
* item2
* item3
⭐ map()을 사용
실무에서는 반복 렌더링 대상이 JSX 배열인 경우보다 문자열이나 객체 등의 값인 경우가 더 많다.
이러한 경우 자바스크립트 Array의 map() 메서드를 사용하면 편리하다.
map()은 배열을 순회하며 조건을 처리 해 새로운 배열로 반환하는 메서드이다.
// 문자열
export default function App()
{
const arr = [ '사과', '바나나', '오렌지' ];
return (
<ul>
{ arr.map((item, index)=>(
<li key={ item }>{ item }</li>
)) }
</ul>
);
}
// 객체
import ListItem from './components/ListItem'
export default function App()
{
const users = [
{ id: 1, name: '엄노니', role: '개발자' },
{ id: 2, name: '제미나이', role: 'AI' },
];
return(<>
{ users.map((user) => (
<ListItem key={user.id} text={`${user.name} (${user.role})`} />
)) }</>);
}
이와 같이 값의 나열로 주어진 배열을 JSX 내부 표현식을 이용해서 간편하게 JSX 요소로 바꿀 수 있다. 컴포넌트도 마찬가지로 map을 사용할 수 있다.
import ListItem from './components/ListItem'
export default function App()
{
const arr = [ '사과', '바나나', '오렌지' ];
return (
<ul>
{ arr.map((item, index)=>(
<ListItem key={ item } text={ item } />
)) }
</ul>
);
}
그 밖의 반복 렌더링(reduce())
자바스크립트에서 사용할 수 있는 반복 조건문을 사용하면, 순수 배열과 map()이외의 요소로도 반복 렌더링을 구현할 수 있다.
하지만 for, forEach의 경우 빈 배열을 선언하고 내부에 push하는 과정이 필요해 비교적 쓰이지 않는 편이다.
또 다른 Array 메서드 중 하나인 reduce()는 빈 배열을 선언하지 않고 반복문 내부에서 조건에 따른 값을 설정할 수 있어 비교적 많이 사용되는 편이다.
export default function App()
{
const arr = [ '사과', '바나나', '오렌지' ];
return (
<ul>
{ arr.reduce<React.ReactNode[]>((acc, item)=>(
acc.push(<li key={item}>{ item }</li>);
return acc;
), []) }
</ul>
);
}
반복 렌더링 비교표
