이 글은 React, React Native에서 논리 연산자로 조건부 렌더링할 때의 주의사항에 대해 설명한다.
JSX 안에는 중괄호를 이용해 표현식을 포함할 수 있다.
그 안에 javascript 논리 연산자 &&를 사용하면 쉽고 간결하게 엘리먼트를 조건부로 렌더링할 수 있다.
&& 연산자는 왼쪽 피연산자가 true로 간주되면 오른쪽 피연산자를, false로 간주되면 해당 리터럴을 반환한다.
다시 말해서 a&&b의 결과는 a가 true로 간주된다면 a, false로 간주된다면 b이다.
컴포넌트나 엘리먼트를 논리 연산자 &&를 이용해 조건부 렌더링하면, 왼쪽의 피연산자가 true로 간주되는 값일 때 오른쪽의 컴포넌트나 엘리먼트가 렌더링된다.
그러나 컴포넌트 조건부 렌더링 시 왼쪽의 피연산자가 false일 때가 있다면 주의해서 코드를 짤 필요가 있다. 아래 예시를 통해 이를 살펴보자.
예시
ProductCard 컴포넌트는 부모로부터 props를 통해 imgSrc(상품 이미지 url)와 name(상품 이름)을 받아 렌더링한다.
props에 likeCount(좋아요 수)가 존재하면 이 또한 렌더링한다.
과연 아래의 코드는 위에 명시된 대로 렌더링될까?
//React
import React from 'react';
export type ProductCardProps = {
imgSrc: string;
name: string;
likeCount?: number;
};
export default function ProductCard({
imgSrc,
name,
likeCount,
}: ProductCardProps) {
return (
<div>
<img src={imgSrc} alt={imgSrc} />
<p>{name}</p>
{likeCount && <p>{likeCount}</p>}
</div>
);
}
//React Native
import React from 'react';
export type ProductCardProps = {
imageSource: string;
name: string;
likeCount: number;
};
export default function ProductCard({
imageSource,
name,
likeCount,
}: ProductCardProps) {
return (
<View>
<Image source={imageSource} />
<Text>{name}</Text>
{likeCount && <Text>{likeCount}</Text>}
</View>
);
}
javascript에서 false로 간주되는 리터럴에는 false, null, undefined, 0, ''(빈 문자열), NaN 등이 있다.
위 예시에서 likeCount가 0이라면, 0은 false로 간주되기 때문에 해당 값이 반환된다.
이때 몇가지 문제점이 생길 수 있다.
-
React Native에서는 문자열을 렌더링하려면 무조건 문자열을 <Text/> 태그로 감싸야 한다. 위의 경우 0이 Text 태그에 감싸지지 않은 채로 반환되어 앱이 이를 에러로 간주한다.
-
<p/>, <Text/> 태그에 따로 스타일링을 해놓았다면 해당 스타일이 적용되지 않은 채 likeCount가 렌더링될 것이다.
따라서 &&의 왼쪽 피연산자가 false로 간주된다면 해당 값이 반환된다는 것에 유의해야 한다.
위의 코드에서 && 연산자 앞을 아래와 같이 바꿔주면 likeCount가 0일 때애도 원하는 대로 컴포넌트가 렌더링된다.
//React
import React from 'react';
export type ProductCardProps = {
imgSrc: string;
name: string;
likeCount?: number;
};
export default function ProductCard({
imgSrc,
name,
likeCount,
}: ProductCardProps) {
return (
<div>
<img src={imgSrc} alt={imgSrc} />
<p>{name}</p>
{likeCount >= 0 && <p>{likeCount}</p>}
</div>
);
}
//React Native
import React from 'react';
export type ProductCardProps = {
imageSource: string;
name: string;
likeCount: number;
};
export default function ProductCard({
imageSource,
name,
likeCount,
}: ProductCardProps) {
return (
<View>
<Image source={imageSource} />
<Text>{name}</Text>
{likeCount >= 0 && <Text>{likeCount}</Text>}
</View>
);
}