컴포넌트 반복

nasagong·2023년 2월 11일
0

React

목록 보기
7/15
post-thumbnail

📚 들어가며

리액트에서 반복되는 데이터를 렌더링하는 방법을 알아보자. key와 불변성 유지 개념도 배우게 될 것이다.

반복되는 코드

const IterationSample = () => {
    return (
        <ul>
            <li>A</li>
            <li>B</li>
            <li>C</li>
            <li>D</li>
        </ul>
    );
};
export default IterationSample;

html에서 코드를 작성하다보면 같은 형태를 여러번 반복해야 되는 때가 생긴다. jsx에서 이런 코드를 작성할 때는 비교적 단순하게 반복되는 부분을 처리할 수 있다. 일례로 배열을 사용하는 방법이 있다.

데이터 배열을 컴포넌트 배열로 변환하기

const IterationSample = () => {
    const names = ['A','B','C','D'];
    const nameList = names.map(name=><li>{name}</li>);
    return <ul>{nameList}</ul>;
};
export default IterationSample;

map을 통해 기존 리스트의 요소를 각각 리스트 태그를 감싼 새로운 배열을 반환받은 후 이를 렌더링했다. 렌더링 결과는 맨 처음 작성했던 코드와 같다.

key

물론 위 코드를 렌더링 하는 데 자체는 문제가 없었지만 콘솔창을 확인해보면 아래와 같은 오류가 떠있다. key prop이 뭘까 , 왜 필요한걸까?

[사진]

key는 컴포넌트 내 배열에서 어떤 원소에 변동이 있었는지 알아내기 위해 사용된다. key가 없다면 가상 DOM과 비교하는 과정에서 순차적으로 하나하나 비교해야 하지만 , key가 있다면 어떤 변화가 일어났는지 더 빠르게 추적 가능하다.

예제 코드에도 map함수의 내장 index를 사용해 key를 설정해보자.

const IterationSample = () => {
    const names = ['A','B','C','D'];
    const nameList = names.map((name,index)=><li key={index}>{name}</li>);
    return <ul>{nameList}</ul>;
};
export default IterationSample;

위처럼 key를 설정하면 개발자 도구에서 오류를 출력하지 않는다. 다만 알아두어야 할 부분은 예시를 위해 index를 key값으로 사용한 것이지 보통은 바람직하지 않다.

동적인 배열 렌더링하기

지금까지 배운 내용들을 종합해 input으로 입력받은 값을 배열에 추가하고, 더블클릭으로 배열값을 삭제하는 기능을 구현해 볼 것이다.

import { useState } from 'react';

const IterationSample = () =>{
    const [names, setNames] = useState([
        {id : 1, text : '눈사람'},
        {id : 2, text : '얼음'},
        {id : 3 ,text : '눈'},
        {id : 4, text : '바람'}
    ]);
    const [inputText, setInputText] = useState('');
    const [nextId, setNextId] = useState(5);

    const nameList = names.map(name=><li key={name.id}>{name.text}</li>);
    return <ul>{nameList}</ul>;
}
export default IterationSample;

기본적인 틀은 이렇다. 이제 여기에 기능들을 붙여보자.

데이터 추가하기

import { useState } from 'react';

const IterationSample = () => {
	const [names, setNames] = useState([
		{ id: 1, text: '눈사람' },
		{ id: 2, text: '얼음' },
		{ id: 3, text: '눈' },
		{ id: 4, text: '바람' },
	]);
	const [inputText, setInputText] = useState('');
	const [nextId, setNextId] = useState(5);

	const onChange = (e) => setInputText(e.target.value);
    const onClick = () =>{
        const nextNames = names.concat({
            id: nextId,
            text : inputText
        });
        setNextId(nextId + 1);
        setNames(nextNames);
        setInputText('');
    }
	const nameList = names.map((name) => <li key={name.id}>{name.text}</li>);
	return (
		<div>
			<input value={inputText} onChange={onChange} />
            <button onClick = {onClick}>추가</button>
			<ul>{nameList}</ul>
		</div>
	);
};
export default IterationSample;

[렌더링된 사진]

input에 입력한 값을 배열에 배열에 추가해 렌더링하고 있다. 배열 객체의 id값을 key로 사용 중이다. 기본적으로 다 배운 내용이기에 특별한 건 없지만 하나 주목해야 할 부분이 있다

불변성 유지

const onClick = () =>{
        const nextNames = names.concat({
            id: nextId,
            text : inputText
        });
        setNextId(nextId + 1);
        setNames(nextNames);
        setInputText('');
    }

배열을 업데이트하는 부분을 보면, push로 객체 하나를 붙여주는 식이 아닌

  1. concat으로 기존 배열에 값을 추가해주고
  2. 변경된 배열 사본을 만들어주고
  3. 사본을 setNames메소드를 통해 덮어씌워줬다.

앞서 객체나 배열의 state를 일부 수정할 때는 사본을 만들어 덮어씌우는 방식을 사용하라고 배웠다.

리액트에서 상태를 업데이트 할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야 한다. 이를 불변성 유지라고 한다.
불변성 유지를 해주어야 리액트 컴포넌트 성능을 최적화할 수 있다고 하는데 , 관련 내용은 후반부에 알아보도록 하자.

데이터 제거하기

import { useState } from 'react';

const IterationSample = () => {
	const [names, setNames] = useState([
		{ id: 1, text: '눈사람' },
		{ id: 2, text: '얼음' },
		{ id: 3, text: '눈' },
		{ id: 4, text: '바람' },
	]);
	const [inputText, setInputText] = useState('');
	const [nextId, setNextId] = useState(5);

	const onChange = (e) => setInputText(e.target.value);
    const onClick = () =>{
        const nextNames = names.concat({
            id: nextId,
            text : inputText
        });
        setNextId(nextId + 1);
        setNames(nextNames);
        setInputText('');
    }
    const onRemove = id =>{
        const nextNames = names.filter(name => name.id !== id);
        setNames(nextNames);
    }
	const nameList = names.map((name) => <li key={name.id} onDoubleClick={
        ()=>onRemove(name.id)
    }>{name.text}</li>);
	return (
		<div>
			<input value={inputText} onChange={onChange} />
            <button onClick = {onClick}>추가</button>
			<ul>{nameList}</ul>
		</div>
	);
};
export default IterationSample;

완성된 코드다. onDoubleClick이 처음 사용되었다. <li>요소 각각에 더블클릭 이벤트를 할당해 삭제 기능을 구현했다. 배열을 업데이트할 때 역시나 불변성 유지를 위해 filter를 사용해 덮어씌우는 방식을 사용했다. 렌더링해보면 잘 작동한다.

[사진]

🤔 마치며

컴포넌트 반복보다는 불변성 유지 / key에 무게가 많이 실렸던 장이다. 불변성 유지에 대한 정확한 설명이 나오지 않았기에 아직 완전한 이해는 불가하지만 여기서 이걸 더 파고들면 딱히 남는 것도 없고 진도는 진도대로 멈추는 걸 알기에.. 일단은 그렇구나~ 마인드로 넘어가자. 앞으로 마치며도 꼭 쓰면서 내용 간단히 정리할 것....

profile
잘쫌해

0개의 댓글