[Next.js] 데이터 로딩 방식

정호·2026년 4월 15일

Next.js

목록 보기
4/4

[Next.js] 서버 컴포넌트에서 데이터베이스 직접 연결하기

useEffectfetch 없이 서버에서 직접 데이터를 꺼내오는 현대적인 풀스택 로딩 전략을 분석함

키워드: Direct DB Access, RSC async/await, lib 폴더 구조, SQLite


1. 데이터 로딩 방식의 혁신

기존 리액트(CSR)는 브라우저가 API 서버를 호출하고 기다리는 복잡한 과정을 거쳤지만, Next.js 서버 컴포넌트는 서버 내부에서 DB에 직접 접근합니다.

비교 항목기존 리액트 (CSR)Next.js 서버 컴포넌트 (RSC)
통신 방식브라우저 → API 서버 → DB서버 컴포넌트 → DB (직접)
필요한 훅useState, useEffect 필수필요 없음 (async/await 사용)
보안API 엔드포인트 노출 위험서버 내부 실행으로 안전함

2. DB 로직 분리 (lib/meals.js)

데이터베이스 연결과 쿼리 로직은 별도의 lib 폴더에서 관리하여 코드의 가독성과 재사용성을 높입니다.

import sql from 'better-sqlite3';

const db = sql('meals.db');

export async function getMeals() {
  // 로딩 상태 확인을 위해 의도적인 지연(Delay) 추가
  await new Promise((resolve) => setTimeout(resolve, 2000));

  // .all()은 모든 행을 배열로 가져옴
  return db.prepare('SELECT * FROM meals').all();
}

3. 컴포넌트에 async/await를 직접 쓰는 이유

가장 많은 입문자가 헷갈리는 부분입니다. 왜 일반 리액트 컴포넌트는 async가 안 되고, 서버 컴포넌트는 될까요?

① 일반 리액트(CSR)의 한계

일반적인 클라이언트 컴포넌트는 "즉시 UI(JSX)를 반환해야 하는 함수"입니다

  • 문제점: async를 붙이면 함수가 JSX가 아닌 Promise를 반환합니다.

  • 결과: 리액트 엔진은 화면에 그릴 HTML이 필요한데 '나중에 줄게'라는 약속(Promise)을 받으면 에러를 냅니다. 그래서 예전엔 useEffect 안에서 데이터를 따로 관리했습니다.

② 서버 컴포넌트(RSC)의 마법

서버 컴포넌트는 브라우저가 아닌 서버(백엔드 환경)에서 실행됩니다.

  • 기다림의 미학: 서버는 "데이터 가져오는 데 2초 걸려? 오케이, 다 가져올 때까지 내가 기다렸다가(await) 완성된 HTML을 통째로 구워서 보내줄게"라고 할 수 있는 능력이 있습니다.

데이터 로딩 프로세스 변화

  1. 서버 진입: 요청이 오면 서버 컴포넌트 함수가 실행됨.
  2. 비동기 대기: await getMeals() 라인에서 DB 응답이 올 때까지 함수 실행을 잠시 멈춤.
  3. HTML 생성: 데이터가 도착하면 그 데이터를 버무려 최종 HTML을 완성함.
  4. 전송: 브라우저는 자바스크립트가 실행되기 전부터 이미 데이터가 채워진 HTML을 받게 됨.
profile
열심히 기록할 예정🙃

0개의 댓글