'false | void' 형식은 'ReactNode' 형식에 할당할 수 없습니다. (map vs forEach) 그리고 데이터 바인딩!

렐루·2024년 4월 19일
0

넥스트js

목록 보기
4/16


1. 전체코드

import Link from "next/link";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import "dayjs/locale/ko";
import { faker } from "@faker-js/faker";

import style from "./post.module.css";
import ActionButtons from "@/app/(afterLogin)/_component/ActionButtons";
import PostArticle from "./PostArticle";

dayjs.locale("ko");
dayjs.extend(relativeTime);

type Props = {
  noImage?: boolean;
};

export default function Post({ noImage }: Props) {
  const target = {
    User: {
      id: "elonmusk",
      nickname: "Elon Musk",
      image: "/yRsRRjGO.jpg",
    },
    content: "클론코딩 라이브로 하니 너무 힘들어요 ㅠㅠ",
    createdAt: new Date(),
    Images: [] as any[],
    postId: 123,
  };

  if (Math.random() > 0.5 && !noImage) {
    target.Images.push(
      { imageId: 1, link: faker.image.urlLoremFlickr() },
      { imageId: 2, link: faker.image.urlLoremFlickr() },
      { imageId: 3, link: faker.image.urlLoremFlickr() },
      { imageId: 4, link: faker.image.urlLoremFlickr() }
    );
  }

  return (
    <PostArticle post={target}>
      <div className={style.postWrapper}>
        <div className={style.postUserSection}>
          <Link href={`/${target.User.id}`} className={style.postUserImage}>
            <img src={target.User.image} alt={target.User.nickname} />
            <div className={style.postShade} />
          </Link>
        </div>
        <div className={style.postBody}>
          <div className={style.postMeta}>
            <Link href={`/${target.User.id}`}>
              <span className={style.postUserName}>{target.User.nickname}</span>
              &nbsp;
              <span className={style.postUserId}>@{target.User.id}</span>
              &nbsp; · &nbsp;
            </Link>
            <span className={style.postDate}>
              {dayjs(target.createdAt).fromNow(true)}
            </span>
          </div>
          <div>{target.content}</div>
          <div className={style.postImageSection}>
            // 여기가 문제의 코드입니다!!!!!!
            {target.Images && target.Images.length > 0  && 
                target.Images.forEach((image) => <Link href={`/`}></Link> )
              
            }
          </div>
          <ActionButtons />
        </div>
      </div>
    </PostArticle>
  );
}
// 문제 코드!
<div className={style.postImageSection}>
            {target.Images && target.Images.length > 0  && 
                target.Images.forEach((image) => <Link href={`/`}></Link> )
              
            }
          </div>

2. 에러 그리고 해결책

위 코들 작성 중에 다음과 같은 에러 코드를 받았다.

'false | void' 형식은 'ReactNode' 형식에 할당할 수 없습니다.
'void' 형식은 'ReactNode' 형식에 할당할 수 없습니다

애러 내용은 내가 지금 false 또는 void 를 리턴 중이라는데 어딜 봐서 false인지 처음에는 저 논리적 연산자 && 이게 문제인가 싶었습니다.
만약에 평가 결과가 false면(target.Images && target.Images.length > 0) 전체 결과가 false가 되니까요.
근데 또 이상한게 {false} 이렇게 하면 오류가 없어요 뭐지? 싶었습니다...
검색을 해봐도 딱히 마땅한 해결책을 모르겠어서 챗 지피티에게 물어봤습니다.

forEach 메소드는 배열의 각 요소에 대해 주어진 함수를 실행하지만, 아무런 값도 반환하지 않습니다. 리액트 컴포넌트에서 동적으로 여러 요소를 렌더링하려면, map 메소드를 사용해야 합니다. map 메소드는 각 배열 요소에 대해 실행된 함수의 결과를 모아 새로운 배열을 반환합니다. 이 새로운 배열을 컴포넌트의 반환 값에 직접 사용할 수 있습니다.

챗지피티님의 찰떡같은 설명~~ 듣자마자 제가 정말 부족하다는 것을 느꼈습니다.. 그동안 당연하게 map을 쓰고 있었는데 어떻게 forEach와 헷갈릴 수 있는지... 그리고 forEach가 리턴은 항상 undifined 라는 것을 오늘 찾아보면서 깨달았습니다.... ㅠㅜ

3. 의문점? {false}, 데이터바인딩

그럼 이제 꼬리를 무는 질문은 태그 안에

근데 또 이상한게 {false} 이렇게 하면 오류가 없어요

이건 또 왜 되는걸까요?
찾아보다가 "데이터바인딩" 이라는 단어를 알게 되었습니다!!!!
https://codingapple.com/unit/react2-jsx-classname-html/

근데 리액트에서 데이터 바인딩이라는 단어를 찾아보니 꼭 html만을 가르키는 단어는 아니었습니다ㅠㅜ
나는 내가 받은 오류문구과 false가 되면 평가 어떻게 되는지 그리고 언제를 위의 오류 문구에서 말하는 false인지가 궁금했지만 어쩌면 모르는게 많아서 문제 자체에 접근을 못하고 있는 것일수도 있기에 그냥 계속 찾아보기로 했습니다ㅎㅎ

3-1. 데이터 바인딩

💡 화면상에 보여지는 데이터(View)와 브라우저 메모리에 있는 데이터(Model)를 묶어서(Binding) 서로 간의 데이터를 동기화하는 것을 의미합니다.
💡 예를 들어서 HTML에서 서버 혹은 스크립트상에서 받아온 데이터를 화면상에 그려주고 있다고 가정을 했을 때, 해당 값이 변경이 될 경우 다시 HTML 상에 데이터(값)를 변경된 값에 따라서 맞추어 주는 동작을 '데이터 바인딩'이라고 합니다.

참고로 리액트는 단방향 데이터 바인딩이라고 합니다!!

3-2. 조건부 랜더링

위의 상황과 가장 비슷한 상황을 공식문서에서 찾아봤습니다!!
https://react.dev/learn/conditional-rendering

위의 사진에서 봐도 랜더트리의 구멍으로 간주하고 아무것도 안그린다는데 흠...ㅋㅋ 그럼 void나 null, undifined, false 다 되야하는거 아녀??

아쉽지만 제가 좀더 공부해서 왜 이런 오류가 발생했는지 찾아보겠습니다.
조심스러운 추측으로는 typescript가 리액트와는 별개로 만든 오류가 아닌지 생각하고 있습니다..
긴글 읽어주셔서 감사합니다!!!

[참고 자료]
https://adjh54.tistory.com/49

profile
프론트 공부중입니다!

0개의 댓글