๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿชฒ debug

Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined...

React์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ข…์ข… ๋‹ค์Œ๊ณผ ๊ฐ™์€ compound component๋ฅผ ๋งŒ๋“ค์–ด ๋ชจ๋“ˆํ™”๋ฅผ ์‹œํ‚ค๊ณ  ์žฌํ™œ์šฉ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

"use client";
import { MyButton } from "@tripie/design-system";
import { useAppTheme } from "@tripie/hooks";

const ThemeButton = () => {
  const { setControl } = useAppTheme();
  return (
    <MyButton onClick={() => setControl("os_default")}>os default</MyButton>
  );
};

const ToggleButton = () => {
  const { mode, toggle } = useAppTheme();
  return (
    <MyButton onClick={toggle}>
      to {mode === "dark" ? "light" : "dark"}
    </MyButton>
  );
};

ThemeButton.Toggle = ToggleButton;

export default ThemeButton;

 

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ์คฌ์—ˆ๋‹ค.

import ThemeButton from "../components/ThemeButton";

export default function TestPage() {
  return (
    <div>
      <ThemeButton />
      <ThemeButton.Toggle />
      <h1>this is home</h1>
    </div>
  );
}

 

์ž˜๋งŒ ์“ฐ๋˜ ์ฝ”๋“œ๋ฅผ nextjs์—์„œ ์“ฐ๊ณ  ์žˆ๋Š”๋ฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

 

๋ญ๊ฐ€ ๋ฌธ์ ค๊นŒ? ์—๋Ÿฌ๋ฅผ ์ฝ์–ด๋ณด์ž

Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

โจฏ Error: Unsupported Server Component type: undefined

 

๋ฆฌ์•กํŠธ ํƒ€์ž…์ด ์ด์ƒํ•˜๋‹ค๋Š” ๊ฒƒ. ๋‚ด์žฅ๋œ ์ปดํฌ๋„ŒํŠธ๋กœ๋Š” string์„, composite (ํ•ฉ์„ฑ) ์ปดํฌ๋„ŒํŠธ์ผ ๊ฒฝ์šฐ์—๋Š” ํด๋ž˜์Šค๋‚˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•˜์ง€๋งŒ undefined๋ผ๊ณ  ํ•œ๋‹ค. import ๋ฐฉ์‹์— ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ ๋Š” ํ•˜์ง€๋งŒ, default export๋กœ {} ์—†์ด ์ž˜ ๊ฐ€์ ธ์™”์œผ๋‹ˆ ์ž‘๋™ํ•ด์•ผ ํ•œ๋‹ค.

 

๋งˆ์ง€๋ง‰ ์ค„์—์„œ ํžŒํŠธ๋ฅผ ์–ป์—ˆ๋‹ค.

 

Unsupported Server Component type

 

ํ•ด๋‹น compound component๊ฐ€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์ธ๊ฐ€? ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์ธ๊ฐ€?
๋‹ค์‹œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

"use client";
import { MyButton } from "@tripie/design-system";
import { useAppTheme } from "@tripie/hooks";

const ThemeButton = () => {
  const { setControl } = useAppTheme();
  return (
  // ์œ ์ € ์ƒํ˜ธ์ž‘์šฉ์„ ํ†ตํ•ด ํ…Œ๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  // ๋™์ ์ธ ์ƒํ˜ธ์ž‘์šฉ ํ˜น์€ state ๊ด€๋ฆฌ๊ฐ€ ์ˆ˜๋ฐ˜๋œ๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ปดํฌ๋„ŒํŠธ๋‹ค.
    <MyButton onClick={() => setControl("os_default")}>os default</MyButton>
  );
};

const ToggleButton = () => {
  const { mode, toggle } = useAppTheme();
  return (
    <MyButton onClick={toggle}>
      to {mode === "dark" ? "light" : "dark"}
    </MyButton>
  );
};

ThemeButton.Toggle = ToggleButton;

export default ThemeButton;

 

๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ฒ˜์—์„œ "use client"๋ฅผ ์ถ”๊ฐ€ํ•ด ์คฌ๋”๋‹ˆ ์ž˜ ๋Œ์•„๊ฐ„๋‹ค.

"use client";
import ThemeButton from "../components/ThemeButton";

export default function TestPage() {
  return (
    <div>
      <ThemeButton />
      <ThemeButton.Toggle />
      <h1>this is home</h1>
    </div>
  );
}

๐Ÿ™‹ Compound Component๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ปดํฌ๋„ŒํŠธ๋‹ค? 

์•„๋‹ˆ๋‹ค! Compound Component ๋‚ด์—์„œ ์œ ์ € ์ƒํ˜ธ์ž‘์šฉ์ด ์žˆ๊ฑฐ๋‚˜ ๋™์ ์œผ๋กœ state๊ฐ€ ๊ด€๋ฆฌ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ปดํฌ๋„ŒํŠธ์ง€๋งŒ,  ์ •์ ์ธ ์ฝ˜ํ…์ธ ์ธ ๊ฒฝ์šฐ๋‚˜ fetch ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์— ๊ด€๋ จ๋œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๋ฉด ์„œ๋ฒ„ ์ชฝ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋œ๋‹ค.

 

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ compound component๋ฅผ ์“ฐ๋Š” ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

๋‹ค์Œ๊ณผ ๊ฐ™์ด text๋ฅผ ๋ Œ๋” ํ•˜๋Š” ์ •์  ์ฝ˜ํ…์ธ ์˜ compound component๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

const CompositeComponent = () => {
  return <h1>composite component example</h1>;
};

const Option = () => {
  return <h2>hehe i am option!</h2>;
};

CompositeComponent.Option = Option;

export default CompositeComponent;

 

์•ž์„œ ๋ดค๋˜ ๋ฒ„ํŠผ์„ ํฌํ•จํ•œ compound component๊ณผ๋Š” ๋‹ฌ๋ฆฌ ์ •์ ์ธ ์ปดํฌ๋„ŒํŠธ์ด๋ฏ€๋กœ

์•„๋ž˜์˜ ์‚ฌ์šฉ์ฒ˜์—์„œ "use client"๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์•„๋„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

// "use client";
// import ThemeButton from "../components/ThemeButton";

import CompositeComponent from "../components/CompositeComponents";

export default function Home() {
  return (
    <div>
      {/* <ThemeButton /> */}
      {/* <ThemeButton.Toggle /> */}
      <CompositeComponent />
      <CompositeComponent.Option />
      {/* <h1>this is home</h1> */}
    </div>
  );
}

 

 

๐Ÿ€ ์˜ค๋Š˜์€ compound component๋ฅผ ์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ๋ฅผ ์—ผ๋‘ํ•˜๋ฉด์„œ ์จ์•ผ ํ•œ๋‹ค๋Š” ๊ฑธ ์—๋Ÿฌ๋ฅผ ํ†ตํ•ด ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.
๐Ÿค” ๋ฆฌ์•กํŠธ์™€ ๋‹ฌ๋ฆฌ next์—์„œ๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์–ด๋А ์ชฝ์ธ์ง€๋ฅผ ๋” ๊ณ ๋ฏผํ•ด๋ด์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.