우리는 한다, 개발을.

초보자의 눈으로 바라본 Next.js 개발기

⌛ 5 mins

개요

이번 프로젝트에서 Next.js와 Nest.js를 활용하여 간단한 게시판을 구현해 보았습니다. React를 포함해 TypeScript, MUI까지 모두 처음 접하는 기술들이었기 때문에 결과물 자체는 단순했지만, 프로젝트 구성 방식, 폴더 구조의 역할, 소스 파일은 어떤 방식으로 작성되는지 등 개발 흐름을 익히는 데 큰 도움이 되었습니다.

아직은 부족한 점이 많아, 경우와 상황에 맞도록, 유지보수에 편하도록 완벽하게 대응하는 코드를 작성하지는 못한 것 같습니다.(컴포넌트 분리나 레이아웃이나 스타일을 일괄처리 하는 내용 등) 여러 시행착오를 겪으며 새롭게 배운 점과 흥미로웠던 경험을 중심으로 내용을 정리해 보았습니다.

1.State 개념

아래와 같이 form과 input 태그를 사용해 데이터를 서버로 전송하고, 전체 페이지를 새로 고침하는 방식으로 작업해 왔습니다.

일반 HTML

<form action="/submit" method="POST">
    <input type="text" name="Q1">
    <button type="submit">Submit</button>
</form>

React의 상태(State) 관리

React는 일반적으로 SPA(Single Page Application) 방식으로, 페이지 전체를 새로고침하지 않고 컴포넌트 단위로 렌더링합니다. 따라서 데이터를 저장하고 관리하는 방식이 HTML과는 다릅니다.

import { useState } from "react";

function MyComponent() {
  const [inputValue, setInputValue] = useState("");

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={handleChange} />
      <p>입력 : {inputValue}</p>
    </div>
  );
}

useState는 React에서 제공하는 훅으로, 상태값과 이를 업데이트 하는 함수(set)를 반환합니다.

inputValue = 상태값을 저장하는 변수

setInputValue = 상태(inputValue)를 변경하기 위한 함수

inputValue 의 값을 바꾸려면 setInputValue(”입력”) 과 같이 set 함수를 호출하여 변경하여야 합니다.

기존 하드코딩에서 당연하게 작업하던 방식과는 달라서 처음에는 혼란스웠지만, “아 이게 리액트구나” 하면서 가장 설레었던 부분이였습니다.

2. SSR과 CSR

SSR(Server-Side Rendering): 서버에서 HTML을 생성하여 클라이언트에게 전달.

  • 초기 렌더링 속도가 빠르며, SEO에 유리함.

CSR(Client-Side Rendering): 클라이언트 측에서 JavaScript로 렌더링 처리.

  • 초기 로딩 속도는 느리지만 이후 상호작용 속도가 빠름.

React는 기본적으로 CSR방식으로 작동하며, Next JS는 SSR을 기본으로 제공하는 프레임워크 입니다.

Next JS의 특징

useState, useEffect와 같은 React의 훅은 브라우저 환경에서만 동작하기 때문에, 이러한 훅을 사용하는 컴포넌트에서는 Next.js의 지시어인 “use client”를 반드시 선언해야 합니다. Next.js에서는 전체 페이지를 SSR 방식으로 렌더링하면서도, 댓글 입력 폼, 사용자 대시보드 등과 같이 상호작용이 필요한 특정 부분은 클라이언트 컴포넌트로 처리할 수 있어 SSR과 CSR의 장점을 유연하게 조합할 수 있습니다.

- 자동 코드 분할(Automatic Code Splitting)

페이지 단위로 코드가 자동으로 분할되어 필요할 때만 클라이언트로 전송하여 다음과 같은 이점을 제공합니다.

  • 초기 로딩 시간 단축
  • 불필요한 코드 로드 방지
  • 페이지별 효율적인 리소스 관리

3. Cookies vs useCookies

Next JS는 서버와 클라이언트 모두에서 쿠키를 다룰 수 있습니다. 프로젝트를 작업하는 과정에서 로그인 후 사용자 이름을 쿠키에 저장한 뒤 페이지 상단에 “안녕하세요, @@@님.”으로 표시하는 기능을 구현하던 중 사용자 이름이 표시되지 않거나 한 박자씩 늦게 적용되는 것을 발견하고 구글링을 시작하였습니다.

처음에는 쿠키를 설정하면 화면에 바로 반영될 것이라 생각했지만, 아래와 같이 코드를 작성했을 때, 화면에 바로 갱신되지 않는 문제가 발생하였습니다.

❌ Before

const cookies = new Cookies();
cookies.set("userInfo", { ...data }, { path: "/" });

위 내용처럼 쿠키를 설정하는 경우, 브라우저에는 값이 저장되지만 React의 상태(State)와 연결되어 있지 않기 때문에 화면이 즉시 갱신되지 않았던 것이 원인이였습니다.

✅ After

import { useCookies } from "react-cookie";
const [cookies, setCookie, removeCookie] = useCookies(["userInfo"]);
setCookie("userInfo", JSON.stringify(data), { path: "/" });

반면 react-cookie의 useCookies는 내부적으로 React 상태(State)와 연결되어 있어, 쿠키 변경 시 자동으로 리렌더링되어 화면이 즉시 갱신되었습니다.

React의 상태 관리 훅(useState, useEffect 등)과 같이 브라우저 환경에서만 동작하는 기능을 사용할 경우 해당 컴포넌트는 반드시 클라이언트 컴포넌트로 작성해야 합니다.

4. MUI TextField 입력 오류 문제 및 렌더링 최적화

MUI의 TextField를 주로 활용하였는데, style을 적용하는 과정중 컴포넌트에 텍스트를 입력하면 한 글자씩 기입되고 포커스를 잃는 현상이 발생하였습니다. 원인은 잘못된 위치에 styled를 선언하여 렌더링이 발생할 때마다 다시 컴포넌트가 실행되면서 발생하는 문제였습니다.

function MyForm() {
  const Form = styled.form`
    display: flex;
    flex-direction: column;
  `;

  return (
    <Form>
      <TextField label="Input" />
    </Form>
  );
}

- 문제점: styled.form 선언이 함수 내부에 위치함.

리렌더링 시마다 스타일 컴포넌트가 새로 생성되므로, 포커스를 잃게 됨.

const Form = styled.form`
  display: flex;
  flex-direction: column;
`;

function MyForm() {
  return (
    <Form>
      <TextField label="Input" />
    </Form>
  );
}

Styled 컴포넌트를 함수 외부로 이동하여 리렌더링 시 다시 생성하지 않도록 하였습니다.

마치며

하드코딩 외에 개발은 처음이었기에, 단순히 문제를 해결하는 것보다 그 원인을 파악하는데 시간을 많이 들였고, 그 과정이 기초를 이해하는데 큰 도움이 되었습니다. 아직 기초가 부족하여 여러 사이트에서 제공하고 있는 지식을 100% 습득하기에 어려움이 많았습니다. 앞으로도 기초를 탄탄하게 다져나가면서 유용한 정보를 습득하고 공유할 수 있었으면 좋겠습니다.