본문 바로가기
프론트엔드/React

useState vs useEffect

by 느바 2025. 4. 6.
반응형

useState vs useEffect

 

useState와 useEffect는 React의 함수형 컴포넌트에서 가장 자주 사용하는 Hook 중 하나다.

useState

useState는 컴포넌트의 상태(state)를 저장하고 관리할 수 있도록 해주는 Hook이다.

 

const [state, setState] = useState(initialValue);

 

  • state: 현재 상태 값
  • setState: 상태를 업데이트하는 함수
  • initialValue: 초기 상태 값

 

import React, { useState } from 'react';

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

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

이 예시에서는 count라는 상태를 만들고, 버튼을 누르면 setCount로 상태를 업데이트함.

 

React에서 useState로 만든 상태는 해당 컴포넌트 내부에만 저장된다.
즉, React가 내부적으로 컴포넌트별로 상태를 관리하는 메모리 공간이 있고, 거기에 저장된다.

  • 컴포넌트가 렌더링될 때 React는 useState로 만든 상태 값을 기억해두고 있다가
  • 상태가 바뀌면, 그 컴포넌트만 다시 렌더링하면서 새로운 상태 값을 보여준다.

React에서 useState로 만든 상태는 컴포넌트의 인스턴스별로 관리되는 값.

useState로 만든 상태는 그 컴포넌트 안에서만 유효하다. 다른 컴포넌트에서 직접 접근하거나 공유할 수 없다.

function A() {
  const [text, setText] = useState("hello");
  return <B />;
}

function B() {
  // 여기서는 A의 text 상태에 접근할 수 없음 ❌
}

상태를 공유하고 싶으면 상태를 상위 컴포넌트로 올리고(props로 내려주기) 하거나,
전역 상태 관리 도구를 사용해야 한다.

상태 공유 방법 예시1: props로 전달

function Parent() {
  const [text, setText] = useState("hello");

  return (
    <>
      <ChildA text={text} />
      <ChildB setText={setText} />
    </>
  );
}

function ChildA({ text }) {
  return <p>{text}</p>;
}

function ChildB({ setText }) {
  return <button onClick={() => setText("hi!")}>Change</button>;
}

상태 공유 방법 예시 2: 전역 상태 관리 도구 사용

  • Context API
  • Redux
  • Recoil
  • Zustand, Jotai, 등

Context API를 사용한 전역 상태 공유 예시

목표: text 상태를 여러 컴포넌트에서 읽고, 업데이트할 수 있게 만들기!

1. Context 만들기 (TextContext.js)

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

// Context 객체 생성
export const TextContext = createContext();

export function TextProvider({ children }) {
  const [text, setText] = useState("hello");

  return (
    <TextContext.Provider value={{ text, setText }}>
      {children}
    </TextContext.Provider>
  );
}

2. App.js에서 Provider로 감싸기

import React from 'react';
import { TextProvider } from './TextContext';
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';

function App() {
  return (
    <TextProvider>
      <ComponentA />
      <ComponentB />
    </TextProvider>
  );
}

export default App;

3. ComponentA.js – 전역 상태 사용 (읽기)

import React, { useContext } from 'react';
import { TextContext } from './TextContext';

function ComponentA() {
  const { text } = useContext(TextContext);

  return <p>ComponentA sees: {text}</p>;
}

export default ComponentA;

4. ComponentB.js – 전역 상태 사용 (업데이트)

import React, { useContext } from 'react';
import { TextContext } from './TextContext';

function ComponentB() {
  const { setText } = useContext(TextContext);

  return (
    <button onClick={() => setText("world!")}>
      Change Text
    </button>
  );
}

export default ComponentB;

결과

  • ComponentA는 text 상태를 읽기만 하고,
  • ComponentB는 text 상태를 변경한다.
  • 두 컴포넌트가 서로 전혀 몰라도 같은 상태를 공유할 수 있다.

useEffect

useEffect는 컴포넌트가 렌더링될 때 부수 효과(side effect)를 수행할 수 있도록 해주는 Hook이다. 라이프사이클과 관여되있다.

예를 들면:

  • 데이터 불러오기 (fetch)
  • 이벤트 리스너 등록/제거
  • 타이머 설정
  • DOM 조작 등
useEffect(() => {
  // 실행할 코드

  return () => {
    // (선택) 정리(clean-up)할 코드
  };
}, [dependency]);

 

  • dependency: 이 배열에 있는 값이 바뀔 때만 effect가 다시 실행됨
  • 빈 배열 []: 처음 마운트될 때 한 번만 실행

 

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

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

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);

    // 컴포넌트가 언마운트 될 때 타이머 정리
    return () => clearInterval(timer);
  }, []);

  return <p>초: {count}</p>;
}

이 예시에서는 useEffect로 타이머를 만들고, 컴포넌트가 사라질 때 clearInterval로 정리하고 있다.


 

Hook 역할
useState 상태 저장 및 변경
useEffect 컴포넌트 렌더링 후 실행되는 부수효과 처리