Roen의 iOS 개발로그

React 기초6 : key, 조건부 렌더링, 동적 스타일

by Steady On

📣 이 자료는 Udemy의 React 완벽 가이드 강의와 React 공식문서를 참고하여 작성되었습니다.

그리고 개인적으로 공부하고 이해한 내용을 바탕으로 정리하는 용도로 작성되었으므로 이해를 돕기위한 예시는 최소화하였습니다.

 

key?

리액트에서 map 메소드를 사용해서 어떤 컴포넌트를 렌더링할때, 콘솔창에서 이런 key에 관련된 warning을 볼 수 있다. 

key가 필요하다는 경고 문구

여기서 리액트가 말하는 key는 똑같이 생긴 컴포넌트들을 구분할 수 있는, 컴포넌트 각각의 고유한 어떤 표시를 말한다(DB로 보면 id 같은것!). 이런 key를 넣어줘야 하는 이유 중 하나는 리액트의 가상DOM과도 관련이있다.

 

지난 포스팅에서 리액트는 처음에 화면을 그려놓고, 그 똑같은 복사본을 메모리에 가지고 있다가 컴포넌트에 어떤 변화가 감지되면 복사본을 먼저 업데이트 한 후, 진짜 화면과 비교해서 다른 부분만 바꿔치기 한다고 했다.

→ 지난 포스팅 참조 : 2022.08.20 - [Study Note/React] - React 기초3 : Event Listener & Handler, React와 DOM, state

 

이때, key가 없으면 리액트는 똑같은 컴포넌트를 사용한 이 배열을 순차적으로 비교하면서 변화를 감지하려고 한다. 일단 어떤 아이템이 추가 되면, 리액트는 단순히 아이템이 들어있는 배열의 길이가 달라졌다는 것만 인식하기 때문에 이미 렌더링된 아이템의 수를 확인한다. 그리고 배열에 있는 아이템과 하나씩 비교해가면서 없는 것을 찾아내야한다. 그런데 만약에 여기서 새로 추가할 아이템을 목록의 제일 위로 추가하려고 한다면, 리액트는 이 새로 추가된 아이템이 어느위치에 추가되어야 할지 알 수 없어진다. 그래서 리액트는 일단 이 새로운 아이템을 가장 마지막 컴포넌트로 렌더링하고 모든 아이템을 업데이트해서 컨텐츠를 교체 하는 것으로 항목의 순서를 맞춘다. 그럼 결국 이건 성능이 떨어지는 일이고, 버그를 만들 수도 있다(완전히 똑같은 내용의 아이템을 추가한다던지).... 그래서 이런 유니크한 key를 좀 추가해 달라는 경고를 띄우는 것이다.

 

key를 만드는 방법, 추천하지 않는 방법

key를 만들때 절대 추천하지 않는, 리액트에서도 진짜 어지간하지 않으면 하지말라고 하는, 방법이 있는데, 그건 index를 key로 사용하는 것이다. (근데 사실 그렇게 말하지만, key를 정하지 않으면 리액트는 자동으로 인덱스를 key로 사용한다.) 그 이유는 삭제와 추가 동작들이 동시에 일어날때 인덱스가 꼬이면서 엉뚱한 아이템이 삭제될 가능성이 있다.

그럼 key를 어떻게 만들면 좋을까? key를 만드는 방법은 여러가지가 있지만, 가장 흔한 방법은 일단 아이템을 count하는 전역변수를 만들고, 아이템이 추가될 때마다 카운트를 하나씩 올리는 것이다. 개인적으로 이게 제일 깔끔한 것 같다. 중간에 아이템이 삭제되더라도 결번을 채우거나 하지는 않고, 그냥 계속 카운트는 1씩 올라가는 것이다. 하지만 이것도 key로 쓰기에는 너무 단순해서 딱 좋은 방법은 아닌 모양이다.

그래서 참고 글에서 제안하는 방법은 nanoid 라는 라이브러리를 사용하는 것이었다. 하지만, nanoid는 렌더링 중(map메소드로 컴포넌트를 추가할때)에 사용하는 것은 위험하다고 하고 있으므로, 렌더링 할때가 아니라 아이템을 추가할 때 nanoid로 key를 생성해서 넣어주는 방식으로 사용할 것을 추천하고 있다.

 

참고 글 : https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318

 

Index as a key is an anti-pattern

So many times I have seen developers use the index of an item as its key when they render a list.

robinpokorny.medium.com

 

조건부 렌더링

상황에 따라 내용물을 다르게 렌더링 하고 싶을 때 쓸 수 있는 방법이 조건부 렌더링이다. 예를 들어, 어떤 배열을 필터링해서 조건에 해당하는 것만 렌더링 하고 싶다고 하자, 그런데 조건에 맞는 아이템이 하나도 없을 수도 있다. 이럴때, 조건에 맞는게 없으면 다르게 출력할 그것을 어떻게 만드는지 알아보자.

 

중괄호와 삼항 조건식 사용하기

컴포넌트는 일종의 함수이고 그 함수의 return이 컴포넌트가 보여지는 모습이라고 했다. 하지만 return에서는 for문이나 if문 같은 복잡한 js 코드는 쓸 수 없으므로 중괄호로 js 코드를 넣되, 삼항 조건식을 사용해서 return 되는 모습을 달리해 줄 수 있다.

const example = () => {
	const 조건 = 0
    return (
    <div>
    	조건 === 0 ? <p>조건에 해당하는 게 없네요ㅠㅠ</p> : <item />
    </div>
)}

이건 간단한 경우에는 뭐 코드도 그렇게 더러워 보이지 않고, 가독성도 나쁘지 않으니 괜찮은 방법일 수 있다. 이걸 조금만 더 보기 좋게 바꾸려면 논리곱을 사용할 수도 있다.

 

논리곱(&&) 사용하기

const example = () => {
	const 조건 = 0
    return (
    <div>
	    {조건 === 0 && <p>조건에 해당하는 게 없네요ㅠㅠ</p>}
        {조건 === 0 && <item />}
    </div>
)}

그런데, 만약 return 해야할 게 더럽게 복잡하면? 논리곱도 그렇게 좋아보이지 않을 수 있다. 그럼 인제 변수를 추가해서 상태를 바꿔줄 수도 있다.

 

변수로 설정하기

const example = () => {
	const 조건 = 0
    
    let content = <p>조건에 해당하는 게 없네요ㅠㅠ</p>
    if (조건>0) {
    	content = <item />
	}
    
    return <div>{content}</div>
}

이렇게 하면 조금 더 보기에 깔끔해졌다. 하지만 조금만 더 힘을 내보자

 

if문 사용하기

const example = () => {
	const 조건 = 0
    
    if (조건 === 0) {return <p>조건에 해당하는 게 없네요ㅠㅠ</p>}

    return <div><item /></div>
}

이렇게 조건문을 바로 써주고 상황에 맞게 바로 return 해버리는 방법도 있다.

 

하지만 4개중에 뭐가 무조건 더 낫다고 할수는 없으니 상황에 따라 그때그때 깔끔해보이는 코드로 골라쓰면 되겠다.

 

동적 스타일

JS의 어떤 변수의 값을 style에 적용해주는걸 동적 스타일이라고 한다. 변수의 값에 따라 스타일이 바뀌어서 그렇게 부르는것 같다. 예를 들어 색깔을 선택할 수 있게 하고, 그걸 변수에 넣은 다음 style 속성에 전해주면 그 색깔이 반영되거나 하는 식이다. 다른 예로는 그래프의 높이를 변수로 받아서 지정해 줄수도 있다.

const example = props => {
	const color = props.color // 색깔의 이름이 들어있다고 가정하자
    
    return <box style={{backgroundColor: color}} />
}
/* 주의 사항!!
1. CSS 코드를 입력할때, {} 중괄호를 중첩해서 객체로 전달되도록 할것
2. -이 들어가는 키워드의 경우 따옴표로 감싸주거나 카멜표기법을 써서 가운데 단어를 대문자로 써줄것
  -> 안그러면 유효하지 않은 속성 이름이라고 에러가 나요!!

 

 

 

블로그의 정보

Roen의 iOS 개발로그

Steady On

활동하기