동적 렌더링 - 반복 렌더링

#React

반복 렌더링 개념

반복 렌더링배열이나 리스트 형태의 데이터를 기반으로 여러 컴포넌트를 생성해 일관된 방식으로 화면에 출력하는 기법입니다.

반복 렌더링이란 갯수가 변할 수 있는 데이터를 동적으로 렌더링하는 것을 의미한다.

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>
	);
}

반복 렌더링 비교표