업데이트된 next.js 13를 사용해보자. (환경설정편)
next.js는 react에서 SSR을 쉽게 구현할 수 있도록 Vercel에서 만든 프레임워크이다.
초기 웹사이트는 사용자가 다른 페이지로 이동할 때마다 서버에 요청을 해서 새로운 html을 불러와 매번 새로고침되는 방식이었다. 이를 보완하고자 나온 것이 단일 페이지로 최초 한 번 페이지 전체를 로드하는 SPA의 CSR방식이고, 대표적인 SPA 라이브러리가 react 이다.
하지만, 검색엔진 최적화(seo)문제나 초기 페이지 로딩이 오래 걸린다는 문제점이 존재한다. 검색엔진봇은 js를 해석하기 힘들기 때문에 html에서 크롤링을 하는데, CSR방식은 client에서 페이지를 구성하기 전에 빈 html을 보여주기 때문에 검색엔진이 어떠한 정보도 얻기 힘들다.
*구글은 브라우저 내에 Js엔진이 있기 때문에 CSR방식을 사용해도 SEO문제는 없다고 한다.
이때 next.js를 사용하면 앞에 말한 두가지 문제점을 해결할 수 있다.
// next.config.js
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
experimental: {
appDir:true,
}
}
: /app 경로는 아직 시험용이기 때문에 next.config.js파일에 experimental
설정이 필요
css-in-js
형식으로 스타일링을 하면 js코드가 적용되기 전의 페이지가 렌더링되어서 스타일이 적용되는 않은 html 코드가 먼저 렌더링되기 때문에 초기설정이 필요하다.
기존설정
// _document.tsx
export default class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: [initialProps.styles, sheet.getStyleElement()],
}
} finally {
sheet.seal()
}
}
}
-> 13버전부터는 app디렉토리에 _app.tsx , _documents.tsx 는 사용하지 않기 때문에 다른 방식을 사용해야 한다.
// lib/styled-components.tsx
import React from 'react';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
export function useStyledComponentsRegistry() {
const [styledComponentsStyleSheet] = React.useState(
() => new ServerStyleSheet(),
);
const styledComponentsFlushEffect = () => {
const styles = styledComponentsStyleSheet.getStyleElement();
styledComponentsStyleSheet.instance.clearTag();
return <>{styles}</>;
};
const StyledComponentsRegistry = ({
children,
}: {
children: React.ReactNode;
}) => (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children as React.ReactElement}
</StyleSheetManager>
);
return [StyledComponentsRegistry, styledComponentsFlushEffect] as const;
}
useServerInsertedHTML
hook을 사용하여 클라이언트 컴포넌트를 생성한다.'use client';
import { useStyledComponentsRegistry } from '../lib/styled-components';
import { useServerInsertedHTML } from 'next/navigation';
export default function RootStyleRegistry({
children,
}: {
children: React.ReactNode;
}) {
const [StyledComponentsRegistry, styledComponentsFlushEffect] =
useStyledComponentsRegistry();
useServerInsertedHTML(() => {
return <>{styledComponentsFlushEffect()}</>;
});
return <StyledComponentsRegistry>{children}</StyledComponentsRegistry>;
}
3.root layout의 자식들을 style registry component로 감싼다.
import RootStyleRegistry from './RootStyleRegistry';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<RootStyleRegistry>{children}</RootStyleRegistry>
</body>
</html>
);
}
use client
: 타사 npm 패키지의 구성요소에는 자체적으로 "클라이언트 사용"지침이 있기 때문에 서버 구성요소 내에서는 올바르게 작동하지 않는다.그렇기 때문에 css-in-js나 외부라이브러리 등을 사용 시에는 client components
사용해 알려줘야한다.// app/page.tsx
"use client";
import styled from "styled-components";
function Home() {
return <Container>I'm homepage</Container>;
}
export default Home;
const Container = styled.div`
background: red;
`;
*실습에서는 Tailwind CSS와 같은 CSS 파일을 출력하는 다른 방식을 사용하고 있다.