본문 바로가기

Front-End/React

[React, React Native] 논리 연산자 AND(&&)로 조건부 렌더링할 때의 주의사항

이 글은 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>
  );
}