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์์๋ ์๋ฒ์ ํด๋ผ์ด์ธํธ ์ด๋ ์ชฝ์ธ์ง๋ฅผ ๋ ๊ณ ๋ฏผํด๋ด์ผ ํ๋ ๊ฒ ๊ฐ๋ค.