Falsy 와 Truthy

euneun·2021년 12월 4일
1

JS & TS

목록 보기
2/3
post-thumbnail

서론

이 글은

왜 undefined일때 &&로 조건부렌더링이 가능할까?

라는 물음으로 부터 시작되었다 !

리액트에서 특정 조건에따라 컴포넌트를 조건부 렌더링할때,
조건이 boolean 타입일때는 명확하지만,
해당 변수에 값이 있는지 여부로 조건부 렌더링할때는 항상 이게 되나..? 하면서 넘어갔던 것 같아서
정확히 짚고 넘어가려고 한다.

예시 상황

interface IUserInfoProps {
  id: string;
  name: string;
  purchasedProductList?: string[];
} 

const UserInfo: React.FC<IUserInfoProps> = ({ id, name, purchasedProductList }) => {
  return (
    <div>
      <p>{id}</p>
      <p>{name}</p>
      {purchasedProductList.map((purchasedProduct)=><p>purchasedProduct</p>)}
    </div>
  );
};

const Test = () => {
  const [id, setId] = useState('1');
  const [name, setName] = useState('euneun');
  const [purchasedProductList, setPurchasedProductList] = useState(['펜','지우개','연필']);

  useEffect(() => {}, []);

  return <UserInfo id={id} name={name} />;
};

예를 들어 위의 상황에서 purchasedProductList 속성은 optional이기 때문에, 컴포넌트에 전달 되었을수도, 아닐수도있다.
따라서 저런 상황일때 우린 TS2532: Object is possibly 'undefined' 라는 타입스크립트 에러를 마주하게 되는데,

{purchasedProductList?.map((purchasedProduct)=><p>purchasedProduct</p>)}

와 같이 optional chaining 을 이용해서 간단하게 해결 할 수 있지만,
그건 조금 이따가 살펴보기로 하고

습관적으로 다음과같이 &&로 조건부 렌더링 하는 경우를 살펴보자.

{purchasedProductList && purchasedProductList.map((purchasedProduct)=><p>purchasedProduct</p>)}

purchasedProductListtruefalse값이 아닌데 왜 당연하게도 이렇게 사용해왔을까에 대한 의문이 갑자기 들었다.


Falsy 한 값과 Truthy 한 값?

Falsy한 값이란 ?
위에 예시상황의 boolean을 기대하는 문맥에서처럼 , 거짓으로 평가되는 값이다!

MDN에서는 위의 8가지 값을 falsy한 값이라고 정의했는데,
0false는 관습적으로 알 수 있는 내용이고
💡 빈 string, null, undefined, NaN💡 이 falsy한 값이라는 것에 유의해서 보면 좋을 것 같다!

예를 들어 아래와 같은 댓글창을 만들때,
인풋 값이 있냐 없냐에 따라 댓글작성 버튼의 disabled 여부를 정한다고 하면

빈 stringfalsy한 값이기 때문에 아래 코드와 같이 해주면 작동된다.

const [name, setName] = useState('');

return (
  <>
    <input onChange={(e) => setName(e.target.value)} />
    <button disabled={!name} />
  </>
);

또한 위에서

{purchasedProductList && purchasedProductList.map((purchasedProduct)=><p>purchasedProduct</p>)}

이 코드가 작동한 이유도,

purchasedProductListundefined일때는 falsy한 값으로 되어,
&& 뒤의 엘리먼트는 React가 무시하게 된것이다.

이렇게 undefinednullfalsy한 값이라서 not을 해주면 true가 되기때문에
if문에 들어오게되어, 콘솔에 hi가 찍히는 것을 알 수 있다!

내가 습관적으로 하고 있었던것이 falsy, truthy한 값이라서 그렇게 작동하고 있었다는게 신기했다!


함정🧐

함정 1. 그런데 과연, 이렇게 하면 화면에는 아무것도 렌더링 되지 않았을까?

{purchasedProductList && purchasedProductList.map((purchasedProduct)=><p>purchasedProduct</p>)}

예시. 아래코드는 어떻게 렌더링 될까?

falsy한 값들 중 undefined, null, 빈 string의 경우말고 0일 경우도 살펴보자

render() {
  const count = 0;
  return (
    <div>
      { count && <h1>Messages: {count}</h1>}
    </div>
  );
}

아무것도 렌더링되지 않는것이 아니라,
0이 렌더링 된것을 확인 할 수 있다.

같은 맥락을 콘솔로 찍어볼것을 생각해보면 아래의 결과는 어떻게 될까?

console.log(0 && 'hi')

이렇게 알 수 있듯이 falsy 표현식을 반환하면 여전히 && 뒤에 있는 표현식은 건너뛰지만 falsy 표현식이 반환된다는 것에 주의해야 한다.

그동안 falsy0에 대해 다룰 일은 없었고,
undefined, null, ''(빈 string) 값을 주로 조건부 렌더링 시켜서
결국 undefined,null,빈 string이 반환되어 화면에 렌더링 되었던건데
아무것도 렌더링 하지 않았다고 착각하고 있었다.

그리고 nullundefined는 엄연히 다르다는것을 명심해야한다!


optional chaining

{purchasedProductList?.map((purchasedProduct)=><p>purchasedProduct</p>)}

TypeScript 3.7부터 추가된 optional chianing을 이용하면 위와 같이 쓸 수 있다.

? 앞에있는 purchasedProductListundefined또는 null일때는 그 이후의 속성을 찾지 않고, 바로 undefined를 반환하게된다.
&&를 쓸때보다 코드가 훨씬 간단해진다는 장점이 있다.

그렇다면 &&와 차이점은 코드길이밖에 없을까?

MDN에서 설명하는 &&?.연산자의 정의를 찾아보면, 아래와 같이 설명하고 있다.

&&

  • More generally, the operator returns the value of the first falsy operand encountered when evaluating from left to right, or the value of the last operand if they are all truthy.
    -> 반적으로 && 연산자는 왼쪽에서 오른쪽으로 평가할 때 처음 발생한 falsy 피연산자 값을 반환하거나 모두 truthy인 경우 마지막 피연산자의 값을 반환합니다.
    -> 왼쪽false면, 오른쪽은 볼 것도 없이 왼쪽 값을 반
    환한다
    !!!

?.

  • ?. 연산자는 . 체이닝 연산자와 유사하게 작동하지만, 만약 참조가 nullish (en-US) (null 또는 undefined)이라면, 에러가 발생하는 것 대신에 표현식의 리턴 값은 undefined로 단락된다. 함수 호출에서 사용될 때, 만약 주어진 함수가 존재하지 않는다면, undefined를 리턴한다.

한마디로, ?.는 nullish(null 또는 undefined)한지를 보고,
&&falsy한지를 본다는점이 다르다!


nullish operator

  return (
    <div>
      { balance && <h1>잔액: {balance}</h1>}
    </div>
  );

내 실제 잔액으로 받은 balance값이 0원인데,
위에와 같이 &&를 이용해서 조건부렌더링하면 잔액:0원이 뜨는게 아니라
0falsy한 값이기 때문에 falsy 표현식이 반환되어서0만 렌더링 되게 되는 문제점이 있었다.

이러한 오류를 방지하기 위해 nullish operator(??)를 사용할 수 있다.

?? 연산자는, 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자이다.

falsy인지 확인하지않고 null 또는 undefined인지만 확인해서 예기치 않는 동작이 발생할수있는 상황을 줄인다!

// balance가 undeinfed or null 이면 잔액 0원과 다름없다는것을 가정
  return (
    <div>
      <h1>잔액: {balance ?? 0}</h1>
    </div>
  );

다음과 같이 작성하면 내가 의도한대로 balance가 0일때,
0falsy한값이든말든 그건 중요하지않고
0Null이나 undefined가 아니기때문에
왼쪽 피연산자인 balance를 정상적으로 반환하여 잔액:0원이 뜨게된다.


참고

profile
제대로 짚고 넘어가자!🧐

0개의 댓글