์ฌ์ค ๋ ๋ง์๋๋ฐ ๊ธฐ๋กํ๋๊ฑธ ๊น๋จน์ด์ใ
์์ฝ์ง๋ง ์๊ฐ๋๋๊ฒ๋ง ์ ์ด๋ดค๋ค
โก๏ธ ๋ ๋๋ง์ ์ต์ ํํ๊ธฐ ์ํด์
Key๋ React๊ฐ ์ด๋ค ํญ๋ชฉ์ ๋ณ๊ฒฝ, ์ถ๊ฐ ๋๋ ์ญ์ ํ ์ง ์๋ณํ๋ ๊ฒ์ ๋์ต๋๋ค. key๋ ์๋ฆฌ๋จผํธ์ ์์ ์ ์ธ ๊ณ ์ ์ฑ์ ๋ถ์ฌํ๊ธฐ ์ํด ๋ฐฐ์ด ๋ด๋ถ์ ์๋ฆฌ๋จผํธ์ ์ง์ ํด์ผ ํฉ๋๋ค.
๋ฆฌ์กํธ๋ ๋ณ๊ฒฝ์ฌํญ์ ํ์ธํ๊ณ ์
๋ฐ์ดํธ๊ฐ ํ์ํ ๋๋ง ๋ฆฌ๋ ๋๋ง
key๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ๋ฐฐ์ด์ ์ถ๊ฐ๋ ์์ ํ๊ฐ์ง๋ง ๋ฆฌ๋ ๋๋ง! ๋ฐ๋ผ์ key๋ฅผ ์ฌ์ฉํ๋ฉด ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ ์ ์๋ค.
key๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ๋ฐฐ์ด์ ์ถ๊ฐ๋ ์์ ํ๊ฐ์ง๋ง ๋ฆฌ๋ ๋๋งํ ์ ์์๋ ์ด์ ๋ ๋ฆฌ์กํธ๊ฐ ๊ธฐ์กด ๋ ๋๋ง ํ๋ ๋ฐฐ์ด๊ณผ ์๋ก์ด ๋ฐฐ์ด์ ์์๋ฅผ ๋น๊ตํ๊ธฐ ๋๋ฌธ
์๋ฅผ ๋ค์ด ์๋์ ๊ฐ์ ๋ฐฐ์ด์ด
[
{id:0, title: 'title1', content: 'content1' },
{id:1, title: 'title2', content: 'content2' },
{id:2, title: 'title3', content: 'content3' },
]
์ด๋ ๊ฒ ๋ฐ๋์๋ค๊ณ ๊ฐ์ ํด๋ณด์
[
{id:0, title: 'title1', content: 'content1' },
{id:1, title: '2222', content: 'twotwotwo' },
{id:2, title: 'title3', content: 'content3' },
]
๋ฆฌ์กํธ๋ 1๋ฒ ๋ฐฐ์ด์ id: 0๊ณผ 2๋ฒ ๋ฐฐ์ด์ id: 0์,
๋ฆฌ์กํธ๋ 1๋ฒ ๋ฐฐ์ด์ id: 1๊ณผ 2๋ฒ ๋ฐฐ์ด์ id: 1์,
๋ฆฌ์กํธ๋ 1๋ฒ ๋ฐฐ์ด์ id: 2๊ณผ 2๋ฒ ๋ฐฐ์ด์ id: 2๋ฅผ ๋น๊ตํ ๊ฒ์ด๋ค.
2๋ฒ ๋ฐฐ์ด๋ง title๊ณผ content๊ฐ ๋ฐ๋์์ผ๋ฏ๋ก ์ด๊ฒ๋ง ๋ฆฌ๋ ๋๋งํด์ฃผ๋ฉด ๋!
๊ฐ์ด ๋ฐ๋์ง ์์๋ ๋ฐฐ์ด ์ด์ค๋ฐ์ ์ถ๊ฐ ์์ ์ญ์ ๊ฐ ์ผ์ด๋๋ฉด key๊ฐ ๋ฐ๋๊ธฐ ๋๋ฌธ์ ๋งค๋ฒ ๊ฐ์ด ๋ฐ๋์๋ค๊ณ ์ธ์ํ๊ณ ๋นํจ์จ์ ์ธ ๋ฆฌ๋ ๋๋ง์ ํ๊ฒ ๋๋ค.
๋ฐ๋ผ์ index๋ฅผ key๋ก ์ฌ์ฉํ๋๊ฒ์ ์ง์ํ์!
๊ทธ๋ฐ๋ฐ ์ด๋ฒ ํ๋ก์ ํธ์ ๊ฒฝ์ฐ ์์ , ์ถ๊ฐ, ์ญ์ ์ ๊ฐ์ ๋์์ด ๋ฐ์ํ์ง ์์๋ค.
๊ทธ๋ฅ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ index๋ฅผ key๋ก ์ฌ์ฉํด๋ ๊ด์ฐฎ๋ค๊ณ ํ๋จ!
๊ทธ๋์ ๊ทธ๋ฅ eslint๋ฅผ ์์ ํ๋ค
// key๊ฐ์ผ๋ก index๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก
"react/no-array-index-key": "off",
๋ฐ์ดํฐ๋ฅผ ๋ก์ปฌ์ ์๋ result.json์์ ๊ฐ์ ธ๋ค ์ฌ์ฉํ๋๋ฐ jsx์์ ์ค๋ฐ๊ฟ ๋ฌธ์ \n
์ด ๋์ํ์ง ์์๋ค.
"desc": [
"ํ ๋ฌ ๋์ ๊ณ ๋ฏผํด์ ์ฐ ๊ฐ๋ฐฉ์ ์น๊ตฌ๋คํํ
\n ์๋ํ๋๋ฐ ์น๊ตฌ๋ค ๋ฐ์์ด ์ ์ํฐ๋ฅํ๋ค์. ๋ญ,\n ๋๋ ์ ๋ง ๋ง์์ ๋ค์ด์ ์๊ด์์ด์.",
...
],
๊ทธ๋์ <br/>
์ ์ฌ์ฉํ๋๋ฐ ๊ทธ๊ฒ๋ ๊ทธ๋ฅ ํ ๋ฌ ๋์ ๊ณ ๋ฏผํด์ ์ฐ ๊ฐ๋ฐฉ์ ์น๊ตฌ๋คํํ
<br/> ์๋ํ๋๋ฐ ์น๊ตฌ๋ค ๋ฐ์์ด ์ ์ํฐ๋ฅํ๋ค์.
์ด๋ฐ์์ผ๋ก ๊ทธ๋๋ก ๋์๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ง์ง ๊ฐ๋จํ๋๋ฐ ์ฐพ๋๋ฐ ์งฑ์ค๋๊ฑธ๋ ธ๋ค.
๋ฐ๋ก css์์ white-space:pre-wrap
์ค์ ํ๊ธฐ!
๊ทธ๋ผ ์ค๋ฐ๊ฟ ๋ฌธ์ \n
๋ฅผ ์ธ์ํ๊ณ ์ค ๋ฐ๊ฟํ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํด์ค๋ค.
CSS white-space ์์ฑ์ ์์๊ฐ ๊ณต๋ฐฑ ๋ฌธ์๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฒ์ ์ง์ ํฉ๋๋ค.
ํ์ ์ง์ ์ ์ํด์คฌ๊ธฐ ๋๋ฌธ!
CSS์๋ ํ์ ์ง์ ์ ํด์ฃผ๋ฉด ๋จ!
์ฌ์ค ์๋ฌ๋ ์๋๊ณ ์ฒ์ ์ฌ์ฉํด๋ด์ ๊ทธ๋ฅ ๋ผ์๋๋ค.
์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์ฐ์ฐ๋ ๊ฐ์ ์ฌ์ฌ์ฉํ๋๋ฐ ์ฌ์ฉํ๋ค.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Returns a memoized value.
์ฌ์ฉ ๋ฐฉ๋ฒ
ํ์ ์์ useMemo๋ฅผ ์ฌ์ฉํ ๋ถ๋ถ๋ง ์๋ผ์๋ค!
const quiz = ({ data }: any) => {
const [steps, setStep] = useState<number>(0);
// data๋ผ๋ ๋ฐฐ์ด์ด ์๊ณ ์ฐ๋ฆฌ๋ ๊ทธ ๋ฐฐ์ด์์ ํด๋น step์ธ ๋ฐ์ดํฐ๋ง ๋ณด์ฌ์ฃผ๊ณ ์ถ์
// ์๋ฅผ๋ค์ด step์ด 1์ด๋ฉด data ๋ฐฐ์ด์ 1๋ฒ์งธ ์์๋ง ๋ณด์ฌ์ค
// memoization ํ ๊ฐ step
const currentData = useMemo(() => data[steps], [steps]);
... ์๋ต
const handleClickNextStep = (ans: AnswerProps) => {
// step์ด 8๊น์ง ์๊ธฐ ๋๋ฌธ์ 8์ด ์๋๋ฉด +1 ์ ํด์ค
if (steps !== 8) {
setStep((step) => step + 1);
return;
}
};
... ์๋ต
);
};
head์ ์คํ์ผ ์ํธ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์๋๋ฐ ๋ฐ๋ก ๋ง๋ค๊ธฐ ๊ท์ฐฎ์์ ๊ทธ๋ฅ SEO๋ฅผ ์ํด ๋ง๋ค์ด๋ Headํ๊ทธ ๋ด์ ์คํ์ผ ์ํธ๋ฅผ ์ถ๊ฐํ๋๋ ์ด๋ฐ ์๋๊ฐ ๋ด๋ค.
We don't recommend this pattern because it will potentially break when used with Suspense and/or streaming. In these contexts, next/head tags aren't:
โก๏ธ suspense ๋๋ ์คํธ๋ฆฌ๋ฐ๊ณผ ํจ๊ป ์ฌ์ฉ์ ๊นจ์ง ์ ์๊ธฐ ๋๋ฌธ
- guaranteed to be included in the initial SSR response, so loading could be delayed until client-side rendering, regressing performance.
โก๏ธ ์ฒซ SSR ์๋ต์ ํฌํจ๋๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ ์ธก ๋ ๋๋ง๊น์ง ๋ก๋๊ฐ ์ง์ฐ๋ ์ฑ๋ฅ์ด ์ ํ๋ ์ ์์- loaded in any particular order. The order that the app's Suspense boundaries resolve will determine the loading order of your stylesheets.
โก๏ธ ํน์ ์์๋ก ๋ก๋
์ฑ์ Suspense ๋ฐ์ด๋๋ฆฌ๊ฐ ํด๊ฒฐ๋๋ ์์๊ฐ ๋น์ ์ Stylesheets์ ๋ก๋ฉ ์์๋ฅผ ๊ฒฐ์ ํจ
๋ฅ์คํธ ๊ณต์๋ฌธ์ ์ฐธ์กฐํ๊ธฐ
Suspense lets components โwaitโ for something before rendering.
โก๏ธ suspense๋ ๋ ๋๋ง ์ ์ด๋ค ๊ฒ์ ์ํด ์ปดํฌ๋ํธ๊ฐ ๊ธฐ๋ค๋ฆฌ๋๋ก ํด์ฃผ๋ ๊ฒ
์์ง ๋ ๋๋ง์ด ์ค๋น๋์ง ์์ ์ปดํฌ๋ํธ๊ฐ ์์๋ ๋ก๋ฉ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ณ ๋ก๋ฉ์ด ์๋ฃ๋๋ฉด ํด๋น ์ปดํฌ๋ํธ๋ฅผ ๋ณด์ฌ์ฃผ๋ React์ ๋ด์ฅ๋์ด ์๋ ๊ธฐ๋ฅ์ด๋ผ๊ณ ํ๋ค.
์น์ ํ๊ฒ ๊ณต๋ฌธ์ ํด๊ฒฐ๋ฒ๋ ๋์์์
Add the stylesheet in a custom Document component.
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head>
<link rel="stylesheet" href="..." />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
โก๏ธ document๊ฐ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์๋ง ์ ์๋ ์ ์ญ ๋ณ์๊ธฐ ๋๋ฌธ์ด๋ค.
Next๋ ๋ฆฌ์กํธ๋ฅผ SSR ๋ฐฉ์์ผ๋ก ๊ตฌํํ ์ ์๋๋ก ๋์์ฃผ๋ ํ๋ ์์ํฌ๋ก ์ฒซ ๋ ๋๋ง์ด SSR ๋ฐฉ์์ผ๋ก ์ด๋ฃจ์ด์ง๋ค.
๋ฐ๋ฉด document๋ CSR์ด ๋์ํ ๋ ์ฆ, view ๋ฟ๋ง ์๋๋ผ ์น ํ์ด์ง๋ฅผ ๋์ํ๋ ์์๋ค์ด ๋ชจ๋ ํด๋ผ์ด์ธํธ์ ๋ก๋๋์์ ๋ ์ ์๋๋ค.
๋ฐ๋ผ์ SSR์ด ์คํ๋ ๋ document์ ์ ๊ทผํ ์ ์๋ ๊ฒ์ด๋ค.
์ฐธ๊ณ ๋ก window๋ ๊ฐ์ ์ด์ ๋ก ์๋ฌ๊ฐ ๋ฐ์ํจ!
๊ฐ์ฅ ๋จ์ํ ํด๊ฒฐ ๋ฐฉ๋ฒ!
window๋ document๊ฐ undefined๊ฐ ์๋ ๋ ์ฝ๋๊ฐ ์คํ๋๋๋ก ๋ง๋ค๋ฉด ๋๋ค!
if (typeof window !== 'undefined') {
// Client-side-only code
์คํํ ์ฝ๋ ์
๋ ฅ!
}
์ด๋ฏธ์ง ๋ ๋๋ง, ํฐํธ๋ SEO, ํผํฌ๋จผ์ค ๊ฐ์ ํ ๋ฐฉ๋ฒ์ผ๋ก ใฑใฑใฑ