Post

React 기초 개념 정리 (2) | useState·useEffect 흐름

상태 변화와 사이드 이펙트가 렌더링에 어떤 영향을 주는지 흐름으로 이해해봅니다.

React 기초 개념 정리 (2) | useState·useEffect 흐름

1. useState

1-1. 특징

  • useState컴포넌트 안에서 변하는 값을 저장하고,
    값이 바뀌면 UI가 다시 렌더링되게 만드는 상태 저장용 Hook이다.
  • 컴포넌트가 기억해야 하는 데이터를 리액트가 관리하도록 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { useState } from "react";

function Counter() {

  const [count, setCount] = useState(0); 
  const handleClick = () => {
    setCount(count + 1); 
  };

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

export default Counter;

1-2. 비동기 업데이트

  • setCount()즉시 실행되지 않고, 리액트가 다음 렌더링 사이클에서 한 번에 처리(batch) 한다.
  • 따라서 console.log()로 바로 출력하면 이전 값이 표시될 수 있다.
1
2
3
4
5
6
7
8
9
const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  console.log(count); // ❌ 여전히 이전 값
};

// 해결 방법
setCount((prev) => prev + 1);

1-3. 여러 상태를 객체로 묶기

1
2
3
4
5
const [user, setUser] = useState({ name: "jerry", age: 3 });

user.age = 4; // ❌ 직접 변경하면 리렌더링되지 않음

setUser({ ...user, age: 4 }); // 불변성 유지

2. useEffect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log("렌더링 또는 count 변경됨!");
  }, [count]);

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

export default Timer;

2-3. 클린업

1
2
3
4
5
6
7
8
9
useEffect(() => {
  const timer = setInterval(() => {
    console.log("1초 지남");
  }, 1000);

  return () => {
    clearInterval(timer);
  };
}, []);

2-4. 비동기 작업

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { useState, useEffect } from "react";

function PostList() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    async function fetchData() {
      const res = await fetch("url");
      const data = await res.json();
      setPosts(data.slice(0, 5));
    }

    fetchData();
  }, []);

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

3. EventHook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { useState, useEvent, useCallback, useRef, useEffect} from "react";

function EventExample() {
  const [count, setCount] = useState(0);
  const inputRef = useRef(null);
  const [key, setKey] = useState("");

  const handleClick = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  const handleKeyDown = useEvent((e) => {
    setKey(e.key);
  });

  useEffect(() => {
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [handleKeyDown]);

  const focusInput = useCallback(() => {
    inputRef.current.focus();
  }, []);

  return (
    <div style={{ padding: "20px" }}>
      <h2>이벤트 Hook 예시</h2>

      <input
        ref={inputRef}
        placeholder="여기에 포커스 됨"
        style={{ padding: "8px", marginBottom: "10px" }}
      />
      <br />

      <button onClick={handleClick}>클릭 횟수: {count}</button>
      <button onClick={focusInput} style={{ marginLeft: "10px" }}>
        입력창 포커스
      </button>

      <p>눌린 키: {key || "아직 없음"}</p>
    </div>
  );
}

export default EventExample;

4. 핵심요약

Hook역할설명
useState상태 관리값 변경 시 UI 업데이트
useRefDOM 참조포커스·직접 접근
useCallback함수 최적화불필요한 재생성 방지
useEvent이벤트 관리최신 상태 이벤트 처리
useEffect부수효과이벤트 등록·정리, fetch 등


💡 학습정리
리액트 Hook은 상태 → UI 자동 갱신을 기반으로 동작한다.

This post is licensed under CC BY 4.0 by the author.