3 분 소요


1. Next.js v12와 v13의 주요 차이점

Next.js에서 가장 중요한 개념이 바로 렌더링 방식이다.⭐(CSR, SSR, ISR, SSG)

  • Next.js 버전 12까지는 렌더링 방식을 “페이지 단위”로 규정하였다.
    • about 페이지는 SSG로 동작
    • todolist 페이지는 SSR로 동작
    • sample 페이지는 CSR로 동작


하지만 Next.js 13 버전에서는 React 18 버전에서 제시한

  • 서버컴포넌트(서버상에서만 동작 → node.js 환경)
  • 클라이언트컴포넌트(브라우저에서만 동작 → 브라우저 환경)

을 토대로 렌더링 방식이 기존 “페이지 단위”가 아닌 “컴포넌트 단위”로 변경되었다. 컴포넌트 하나 하나가 각각의 렌더링 방식을 가질 수 있게 되었다!!


정리

  • Next.js 버전 12는 페이지 단위가 렌더링 기준
  • Next.js 버전 13은 컴포넌트 단위가 렌더링 기준⭐

위 그림과 같이 서버컴포넌트와 클라이언트컴포넌트가 공존이 가능하다.



2. 클라이언트 컴포넌트 vs 서버 컴포넌트

2.1 node.js 환경과 브라우저 환경

기본적으로 app 폴더 하위의 모든 컴포넌트는 서버컴포넌트이다.⭐⭐

"use client" 표시가 없으면 무조건 서버컴포넌트!


  • 크롬 브라우저가 아니라 서버를 돌리고 있는 localhost인 내 컴퓨터의 node 환경에서 console.log가 출력되고 있다.
  • 만약 aws 같은 클라우드 컴퓨팅에서 돌아가고 있다면, 사용자의 브라우저가 아니라 해당 서버의 로그에 console.log가 출력될 것이다.
  • 이처럼 컴포넌트의 실행 환경이 브라우저인지, 서버인지에 따라 서버컴포넌트인지 클라이언트 컴포넌트인지가 결정된다.


  • 위와 같이 "use client" 를 적어주면 브라우저에 console.log가 출력되고 있는 것을 확인할 수 있다.
  • 서버 컴포넌트에서는 alert, confirm 처럼 유저와의 상호작용이 필요한 메서드, 기능은 사용할 수 없지만, “use client”;를 컴포넌트 최상단에 붙히면 사용할 수 있게 된다.


컴포넌트에 alert(“hello”)를 출력해보자

import React from "react";

alert("경고!!");
const Home = () => {
  return <div>Home</div>;
};

export default Home;

alert는 서버 컴포넌트에서(Node.js 런타임 환경)는 사용할 수 없는 것을 확인할 수 있다.


2.2 SC CC의 사용

아래 예시를 "use client";를 넣은 상태에서 1회 테스트 + 뺀 상태에서 1회 테스트를 해보자

"use client";

import { useEffect, useState } from "react";

// src>app>page.tsx
export default function Home() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("렌더링이 완료되었습니다.");
  }, []);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div className="p-8">
      행복한 하루 보내세요!
      <div>{count}</div>
      <button onClick={handleClick}>클릭</button>
    </div>
  );
}


  • “use client”가 없다면, 오류가 발생하는 것을 확인할 수 있다.
  • 앞으로 아래와 같은 오류가 발생한다면 클라이언트 컴포넌트로 변경해야한다.


언제 클라이언트 컴포넌트(SC), 서버 컴포넌트(CC)를 사용할까?

Next.js 공식문서에선 User와의 상호작용이 있는 경우 CC를, 그 외의 경우는 SC를 쓰도록 권장하고 있다.



3. 컴포넌트 분리하기

3.1 예시1

만약 이런 코드가 있다고 가정해보자

// src > app > page.tsx
export default function Home() {
  return (
    <div className="p-8">
      안녕하세요! 내배캠 리액트.. 아니아니 넥스트입니다!
      <section>
        <h1>제목</h1>
        <p>내용</p>
        <ul>
          <li>항목1</li>
          <li>항목2</li>
          <li>항목3</li>
        </ul>
      </section>
      <button
        onClick={() => {
          alert("안녕하세요!");
        }}
      >
        클릭
      </button>
    </div>
  );
}
  • 위 코드는 “use client”가 없기 때문에 서버에서만 동작한다.(서버 컴포넌트)
  • useEffect, useState, onClick 등은 클라이언트 컴포넌트에서만 사용 가능한 기술이기 때문에 오류가 발생한다.

그렇다면 "use client";을 사용하면 되는 것 아닌가??!

아니다!!!! onClick 하나 때문에 모든 컴포넌트의 모든 구성요소가 클라이언트 컴포넌트로 만들어버리는 것은 엄청난 낭비이다. (Next.js를 사용하는 이유 없어짐)


“default는 서버 컴포넌트이다. 꼭 필요한 곳에만 “use client”를 이용해서 클라이언트 컴포넌트로 만들어야 한다.” 는 것을 명심하자!⭐⭐⭐

yarn build
yarn start


아래와 같이 컴포넌트 분리를 할 수 있다.

  • 서버 컴포넌트
// src > app > page.tsx
import Button from "@/components/Button";

export default function Home() {
  return (
    <div className="p-8">
      안녕하세요! 내배캠 리액트.. 아니아니 넥스 트입니다!
      <section>
        <h1>제목</h1>
        <p>내용</p>
        <ul>
          <li>항목1</li>
          <li>항목2</li>
          <li>항목3</li>
        </ul>
      </section>
      <Button />
    </div>
  );
}
  • 클라이언트 컴포넌트
// src > components > Button.tsx
"use client";

import React from "react";

const Button = () => {
  return (
    <button
      onClick={() => {
        alert("안녕하세요!");
      }}
    >
      클릭
    </button>
  );
};

export default Button;


3.1 예시2

아래 예시도 컴포넌트 분리를 해보자

분리 전

// src > app > page.tsx
"use client";

import { useEffect, useState } from "react";

// src>app>page.tsx
export default function Home() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("렌더링이 완료되었습니다.");
  }, []);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div className="p-8">
      안녕하세요! 내배캠 리액트.. 아니아니 넥스트입니다!
      <div>{count}</div>
      <button onClick={handleClick}>클릭</button>
    </div>
  );
}


분리 후

  • 서버 컴포넌트
// src > app > page.tsx
import Counter from "@/components/Counter";

export default function Home() {
  return (
    <div className="p-8">
      안녕하세요! 내배캠 리액트.. 아니아니 넥스트입니다!
      <Counter />
    </div>
  );
}
  • 클라이언트 컴포넌트
"use client";

import React from "react";

import { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <div>{count}</div>
      <button onClick={handleClick}>클릭</button>
    </div>
  );
};

export default Counter;



카테고리:

업데이트:

댓글남기기