레이블이 useEffect인 게시물을 표시합니다. 모든 게시물 표시
레이블이 useEffect인 게시물을 표시합니다. 모든 게시물 표시

2025년 1월 18일 토요일

13. 클라이언트 사이드 데이터 페칭 – Next.js에서 클라이언트 사이드 데이터 가져오기

 웹 개발에서 데이터는 중요한 역할을 합니다. 데이터를 어떻게 가져오느냐에 따라 사용자 경험이 크게 달라질 수 있습니다. 이번 글에서는 Next.js에서 클라이언트 사이드 데이터 페칭을 구현하는 방법에 대해 다루겠습니다. 클라이언트 사이드 데이터 페칭이 무엇인지, 왜 중요한지, 그리고 Next.js에서 이를 어떻게 구현할 수 있는지 쉽게 설명하겠습니다.

클라이언트 사이드 데이터 페칭, Next.js 데이터 페칭, useEffect, fetch API, 클라이언트 데이터 요청


1. 클라이언트 사이드 데이터 페칭이란?

클라이언트 사이드 데이터 페칭은 웹 애플리케이션에서 사용자 브라우저(클라이언트)에서 데이터를 가져오는 방식입니다. 즉, 서버에서 데이터를 가져오는 것이 아니라, 페이지가 로드된 후 클라이언트에서 직접 데이터를 요청하는 방식입니다. 이를 통해 페이지가 처음 로드될 때 필요한 데이터를 미리 불러와 사용자에게 빠르게 보여줄 수 있습니다.

클라이언트 사이드에서 데이터를 페칭하는 이유는 사용자 경험을 개선하고, 빠른 페이지 반응 속도를 제공할 수 있기 때문입니다. 예를 들어, 특정 사용자 정보를 페이지가 로드된 후에 불러오는 방식으로, 초기 페이지 로딩은 빠르게 진행될 수 있습니다.


2. Next.js에서 클라이언트 사이드 데이터 페칭 구현하기

Next.js는 클라이언트 사이드에서 데이터를 쉽게 페칭할 수 있도록 돕는 여러 가지 방법을 제공합니다. 그 중에서 가장 많이 사용되는 방법은 useEffect 훅과 fetch API를 활용하는 것입니다.

예시: 클라이언트 사이드 데이터 페칭 구현하기

다음은 useEffect 훅과 fetch를 이용하여 API에서 데이터를 클라이언트 사이드로 가져오는 방법입니다.


import { useState, useEffect } from 'react'; export default function Posts() { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchPosts = async () => { const res = await fetch('https://jsonplaceholder.typicode.com/posts'); const data = await res.json(); setPosts(data); setLoading(false); }; fetchPosts(); }, []); if (loading) { return <p>Loading...</p>; } return ( <div> <h1>Posts</h1> <ul> {posts.map((post) => ( <li key={post.id}>{post.title}</li> ))} </ul> </div> ); }

위 코드에서 useEffect는 컴포넌트가 렌더링된 후 API에서 데이터를 가져옵니다. fetch는 데이터를 비동기적으로 요청하고, 받아온 데이터를 상태에 저장하여 화면에 출력합니다. 이 방식은 클라이언트 사이드에서만 데이터 페칭을 진행하며, 서버는 데이터를 미리 렌더링하지 않습니다.


3. 클라이언트 사이드 데이터 페칭의 장점

클라이언트 사이드에서 데이터를 페칭하는 방식은 여러 가지 장점을 제공합니다.

  1. 빠른 초기 로딩: 페이지 로딩이 빠르고, 필요한 데이터는 클라이언트에서 비동기적으로 가져오기 때문에, 서버에서 렌더링할 필요가 없습니다.
  2. 유연성: 사용자 상호작용에 따라 실시간으로 데이터를 갱신할 수 있으며, 페이지가 새로고침되지 않아 사용자 경험이 향상됩니다.
  3. 서버 부하 감소: 서버는 페이지를 미리 렌더링하지 않기 때문에, 서버 부하를 줄일 수 있습니다. 클라이언트가 데이터를 요청하고, 서버는 데이터만 전달하면 되므로 효율적입니다.

4. 클라이언트 사이드 데이터 페칭과 서버 사이드 데이터 페칭의 차이점

  • 클라이언트 사이드 데이터 페칭: 데이터를 클라이언트(브라우저)에서 요청하고, 페이지 로딩 후에 데이터를 동적으로 가져옵니다. 사용자 경험을 개선할 수 있지만, 초기 페이지 로딩에 시간이 더 걸릴 수 있습니다.
  • 서버 사이드 데이터 페칭: 페이지가 서버에서 렌더링될 때 데이터를 가져옵니다. 이는 초기 페이지 로딩 속도를 빠르게 할 수 있지만, 데이터가 변할 때마다 서버에서 새로 렌더링해야 합니다.

5. 결론

클라이언트 사이드 데이터 페칭은 사용자 경험을 최적화하는 데 중요한 역할을 합니다. Next.js에서는 **useEffect**와 fetch API를 활용하여 손쉽게 클라이언트 사이드에서 데이터를 페칭할 수 있습니다. 이를 통해 빠른 초기 로딩실시간 데이터 갱신을 가능하게 하며, 효율적인 서버 관리가 가능합니다. 다양한 상황에 맞게 클라이언트 사이드와 서버 사이드 데이터를 적절히 사용하면 더 나은 웹 애플리케이션을 개발할 수 있습니다.

14 커스텀 훅(Custom Hook) 만들기: 재사용 가능한 훅 설계와 실제 프로젝트 활용 예시

 React에서 훅(Hook)은 상태 관리와 생명주기 관련 기능을 컴포넌트에 적용할 수 있게 해주는 함수입니다. 기본 훅 외에도 개발자가 자신만의 **커스텀 훅(Custom Hook)**을 만들어 재사용 가능한 코드를 작성할 수 있습니다. 이번 글에서는 커스텀 훅을 만드는 방법과 실제 프로젝트에서 어떻게 활용할 수 있는지에 대해 다뤄보겠습니다. 커스텀 훅을 통해 코드의 가독성, 유지보수성, 재사용성을 높이는 방법을 함께 살펴보겠습니다.

커스텀 훅, React 훅, useState, useEffect, React 커스텀 훅, 폼 입력 관리, React 폼, useForm 훅, API 요청 훅, React 코드 재사용


1. 커스텀 훅이란 무엇인가요?

커스텀 훅은 React의 기본 훅을 활용하여 특정 기능을 재사용할 수 있도록 만든 함수입니다. 기본 훅(useState, useEffect, useContext 등)을 조합하여 필요한 로직을 캡슐화하고, 여러 컴포넌트에서 이를 재사용할 수 있도록 해줍니다.

a. 커스텀 훅의 기본 구조

커스텀 훅은 반드시 use로 시작하는 함수명으로 정의해야 합니다. 이는 React에서 훅을 구별하는 규칙입니다. 예를 들어, useFetch라는 훅을 만들어 데이터를 가져오는 기능을 구현할 수 있습니다.


import { useState, useEffect } from 'react'; // 커스텀 훅 예시: useFetch function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url) .then((response) => response.json()) .then((data) => { setData(data); setLoading(false); }) .catch((error) => { setError(error); setLoading(false); }); }, [url]); return { data, loading, error }; }

위 코드에서 useFetch는 주어진 url에서 데이터를 가져오는 커스텀 훅입니다. 이 훅은 data, loading, error 상태를 관리하고, 이를 호출한 컴포넌트에서 재사용할 수 있게 해줍니다.


2. 커스텀 훅 만들기: 재사용 가능한 훅 설계

커스텀 훅을 만들 때 중요한 점은 코드의 재사용성을 높이고, 다른 컴포넌트에서 손쉽게 활용할 수 있도록 설계하는 것입니다. 커스텀 훅은 복잡한 로직을 분리하고, 여러 컴포넌트에서 동일한 기능을 반복하지 않도록 돕습니다.

a. 예시: 폼 입력 관리 훅 만들기

사용자가 입력한 값을 관리하는 폼을 여러 곳에서 사용한다면, 이를 관리하는 커스텀 훅을 만들 수 있습니다. 이 훅을 통해 입력 값, 오류 메시지, 폼 검증 로직을 간단하게 처리할 수 있습니다.


import { useState } from 'react'; // 커스텀 훅 예시: useForm function useForm(initialValues) { const [values, setValues] = useState(initialValues); const [errors, setErrors] = useState({}); const handleChange = (e) => { const { name, value } = e.target; setValues({ ...values, [name]: value, }); }; const validate = () => { let formErrors = {}; if (!values.name) { formErrors.name = '이름을 입력해주세요'; } if (!values.email) { formErrors.email = '이메일을 입력해주세요'; } setErrors(formErrors); return formErrors; }; return { values, errors, handleChange, validate, }; }

위 예시에서 useForm 훅은 name, email 등의 필드를 가진 폼의 입력 값을 관리하고, 입력 값이 비어 있을 경우 오류 메시지를 반환합니다. useForm 훅을 사용하면 여러 폼에서 같은 로직을 반복하지 않고, 코드의 중복을 줄일 수 있습니다.

b. 커스텀 훅을 사용한 컴포넌트 활용

커스텀 훅은 실제 컴포넌트에서 어떻게 활용될까요? 아래 예시에서는 useForm 훅을 활용하여 간단한 회원 가입 폼을 구현해 보겠습니다.


import React from 'react'; import { useForm } from './useForm'; // useForm 훅 임포트 function SignUpForm() { const { values, errors, handleChange, validate } = useForm({ name: '', email: '' }); const handleSubmit = (e) => { e.preventDefault(); const formErrors = validate(); if (Object.keys(formErrors).length === 0) { // 폼 제출 처리 로직 console.log('폼 제출:', values); } }; return ( <form onSubmit={handleSubmit}> <div> <label>이름:</label> <input type="text" name="name" value={values.name} onChange={handleChange} /> {errors.name && <p>{errors.name}</p>} </div> <div> <label>이메일:</label> <input type="email" name="email" value={values.email} onChange={handleChange} /> {errors.email && <p>{errors.email}</p>} </div> <button type="submit">회원 가입</button> </form> ); } export default SignUpForm;

SignUpForm 컴포넌트에서는 useForm 훅을 사용하여 폼 상태와 검증을 처리하고 있습니다. 이렇게 하면 폼 관련 로직을 useForm 커스텀 훅에서 분리하여 재사용할 수 있습니다.


3. 커스텀 훅을 실제 프로젝트에서 활용하기

커스텀 훅은 복잡한 상태 관리나 공통 기능을 처리할 때 유용합니다. 예를 들어, API 호출, 폼 입력 처리, 애니메이션 상태 관리 등 다양한 상황에서 커스텀 훅을 활용할 수 있습니다.

a. 예시: API 요청을 처리하는 커스텀 훅

여러 컴포넌트에서 같은 API를 호출해야 하는 경우, 이를 하나의 커스텀 훅으로 만들 수 있습니다. 예를 들어, 데이터 목록을 가져오는 useFetchList 훅을 만들 수 있습니다.


import { useState, useEffect } from 'react'; function useFetchList(url) { const [list, setList] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url) .then((response) => response.json()) .then((data) => { setList(data); setLoading(false); }) .catch((error) => { setError(error); setLoading(false); }); }, [url]); return { list, loading, error }; }

useFetchList 훅을 여러 컴포넌트에서 재사용하여 데이터 목록을 가져오고 처리할 수 있습니다. 커스텀 훅을 사용함으로써 코드의 중복을 줄이고, 유지보수성을 높일 수 있습니다.


4. 결론

커스텀 훅을 사용하면 React 애플리케이션의 코드가 더 간결하고 재사용 가능하게 됩니다. useState, useEffect 등의 기본 훅을 활용해 상태 관리나 로직을 캡슐화하고, 이를 여러 컴포넌트에서 재사용할 수 있습니다. 또한, 커스텀 훅을 통해 코드의 유지보수성과 가독성을 향상시킬 수 있습니다.

**커스텀 훅(Custom Hook)**은 특히 복잡한 로직을 여러 컴포넌트에서 공유하고자 할 때 매우 유용합니다. 이를 통해 더 깔끔하고 효율적인 React 애플리케이션을 개발할 수 있습니다.

9 React useEffect 훅과 라이프사이클 완벽 정리

 React의 useEffect 훅은 컴포넌트의 생명주기(lifecycle)와 관련된 작업을 수행할 때 사용됩니다. 이를 활용하면 마운트, 업데이트, 언마운트 시점에서 특정 로직을 실행할 수 있습니다.


useEffect, React useEffect, React 생명주기, 컴포넌트 마운트, 업데이트 시 useEffect, API 호출 React, 타이머 설정 React, React 상태 관리, React 언마운트, useEffect 의존성 배열


1. useEffect 훅 기본 개념

useEffect는 React 컴포넌트에서 사이드 이펙트를 처리하기 위해 사용하는 훅입니다. 주로 데이터 가져오기(API 호출), DOM 업데이트, 타이머 설정과 같은 작업을 수행할 때 활용됩니다.

기본 문법

import React, { useEffect } from 'react';

function ExampleComponent() {
  useEffect(() => {
    console.log('컴포넌트가 렌더링되었습니다.');
  });

  return <div>useEffect 기본 사용법</div>;
}

위 코드는 ExampleComponent가 렌더링될 때마다 useEffect 내부의 코드가 실행됩니다.


2. 마운트, 업데이트, 언마운트 타이밍 다루기

가. 마운트 시점에서 실행

컴포넌트가 처음으로 렌더링될 때만 실행하고 싶다면 useEffect의 두 번째 인자로 빈 배열([])을 전달합니다.

useEffect(() => {
  console.log('컴포넌트가 마운트되었습니다.');
}, []); // 빈 배열을 전달하면 최초 1회만 실행됨

이렇게 하면 컴포넌트가 마운트될 때 한 번만 실행됩니다.


나. 업데이트 시점에서 실행

특정 상태(state)가 변경될 때마다 실행되도록 만들려면 useEffect의 두 번째 인자로 해당 상태를 배열에 추가합니다.

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    console.log(`count 값이 변경됨: ${count}`);
  }, [count]); // count 값이 변경될 때마다 실행됨

  return (
    <div>
      <p>카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}

이렇게 하면 count 값이 변경될 때마다 useEffect가 실행됩니다.


다. 언마운트 시점에서 실행

컴포넌트가 제거될 때(clean-up)를 수행하려면 useEffect 내부에서 return 문을 사용하여 정리(clean-up) 함수를 반환하면 됩니다.

useEffect(() => {
  console.log('컴포넌트가 마운트됨');
  return () => {
    console.log('컴포넌트가 언마운트됨');
  };
}, []);

위 코드는 컴포넌트가 마운트될 때 실행되고, 컴포넌트가 제거될 때 정리(clean-up) 함수가 실행됩니다.


3. useEffect 훅을 활용한 실전 예제

가. API 호출 예제

import React, { useState, useEffect } from 'react';

function FetchData() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then((response) => response.json())
      .then((json) => setData(json));
  }, []);

  return (

API 데이터

{JSON.stringify(data, null, 2)}
); }

위 코드는 API에서 데이터를 가져와 화면에 출력하는 간단한 예제입니다. 마운트될 때 한 번만 실행되도록 설정되었습니다.


나. 타이머 설정 예제

import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, 1000);

    return () => clearInterval(interval); // 언마운트 시 타이머 정리
  }, []);

  return <p>타이머: {seconds}초</p>;
}

이 코드는 컴포넌트가 마운트되면 1초마다 seconds 값을 증가시키고, 언마운트되면 타이머를 정리합니다.


4. useEffect 사용 시 주의할 점

가. 의존성 배열 사용 시 주의

  • 의존성 배열을 정확하게 설정하지 않으면 무한 루프가 발생할 수 있습니다.
useEffect(() => {
  console.log('무한 루프 발생!');
}, [Math.random()]); // 매번 새로운 값이 들어가면서 무한 실행됨

나. 불필요한 렌더링 방지

  • 불필요한 상태 변경이 발생하면 useEffect가 여러 번 실행될 수 있습니다. 이를 방지하려면 상태 변경 로직을 최적화해야 합니다.

5. 정리

React의 useEffect 훅을 활용하면 컴포넌트의 라이프사이클을 효과적으로 관리할 수 있습니다.

  1. 마운트 시 실행 → useEffect(() => {}, [])
  2. 업데이트 시 실행 → useEffect(() => {}, [state])
  3. 언마운트 시 실행 → useEffect(() => { return () => {}; }, [])

또한 API 호출, 타이머 설정 등의 다양한 기능을 처리할 수 있으며, 의존성 배열을 올바르게 설정하여 최적화하는 것이 중요합니다.

위 개념을 활용하여 React 프로젝트에서 효과적으로 상태 관리 및 비동기 작업을 처리해 보세요.