🐨CoalaCoding
DocsExamplesTry itBoardB반
🐨CoalaCoding

개발자를 위한 한국어 웹 기술 문서

문서

  • JavaScript
  • Web Publishing
  • React
  • Python

커뮤니티

  • 게시판
  • 예제 모음
  • Try it 에디터

기타

  • GitHub
  • 관리자
© 2026 CoalaCoding. All rights reserved.
  • 01_hook
  • 02_시작
  • 03_react-vite-설치
  • 04_노코드리액트
  • 05_csrssrreact-렌더링-참조글
  • 06_컴포넌트
  • 07_시작하기
  • 08_2-scaffolding-react-project
  • 09_props
  • 10_3-웹문서-작성하기
  • 11_컴포넌트
  • 12_map과컴포넌트
  • 13_event
  • 14_4-리액트로-변경하기
  • 15_컴포넌트-데이터관리
  • 16_composition
  • 17_앱제작-준비
  • 21_환경설정
  • 24_컴포넌트-전략
  • 25_리액트-네이버-로그인
  • 26_리액트교안
  • 0_React 학습 전 필수 JavaScript 문법
  • 1_React 개발 환경 이해
  • 2_React 소스 코드 수정, 배포 및 렌더링
  • 3_JSX 문법과 컴포넌트
  • 4_Props (속성)
  • 5_이벤트 처리
  • 6_Hook
  • 7_useContext로 전역 상태 관리
  • 8. React Router
  • 9_CSS 리액트에 넣는 5가지 방법
  1. 홈
  2. 문서
  3. React
  4. React 기초
  5. 6_Hook

6_Hook

코드 블록의 Try it Yourself 버튼으로 직접 실행할 수 있다.

구문

1. Hook

Hook은 함수형 컴포넌트에서 React 기능을 사용할 수 있게 해주는 특별한 함수다. 이름이 항상 use로 시작하는 것이 특징이다.

1.1. Hook 사용 규칙

Hook을 사용할 때 반드시 지켜야 할 두 가지 규칙이 있다.

규칙설명
컴포넌트 최상위에서만 호출if문, for문, 중첩 함수 안에서 호출하면 안 된다
React 함수에서만 호출일반 JavaScript 함수에서는 사용할 수 없다
// ❌ 잘못된 예시
function App() {
  if (condition) {
    const [count, setCount] = useState(0); // if문 안에서 호출 → 오류!
  }
}

// ✅ 올바른 예시
function App() {
  const [count, setCount] = useState(0); // 최상위에서 호출
}

1.2. 자주 쓰는 Hook 목록

Hook용도
useState상태(데이터) 관리
useEffect화면 표시/사라짐/업데이트 시 실행
useRefDOM 요소 직접 접근, 렌더링 없이 값 저장
useContext컴포넌트 트리 전체에 데이터 전달
useMemo복잡한 계산 결과 캐싱 (성능 최적화)
useCallback함수 캐싱 (성능 최적화)

이 챕터에서는 가장 많이 쓰는 useState와 useEffect를 집중적으로 다룬다.

2. UseState()

2.1. State란?

State는 컴포넌트의 데이터 저장소다. 값이 변경되면 화면이 자동으로 다시 그려진다.

2.1.1. 기본 사용법

import { useState } from "react";

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

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

2.2. useState 동작 원리

useState는 두 개의 값을 배열로 반환한다.

  • 첫 번째: 현재 상태 값
  • 두 번째: 상태를 변경하는 함수
const [value, setValue] = useState(초기값);

2.2.1. 예제: 카운터

function Counter() {
  const [num, setNum] = useState(0);

  const plus = () => setNum(num + 1);
  const minus = () => setNum(num - 1);

  return (
    <div>
      <h2>{num}</h2>
      <button onClick={plus}>+</button>
      <button onClick={minus}>-</button>
    </div>
  );
}

2.3. 객체와 배열 State 관리

⚠️WARNING

주의: 직접 수정 금지!

상태 객체나 배열을 직접 수정하면 안 된다. 반드시 새로운 객체/배열을 만들어야 한다.

전개 연산자 를 사용하면 편리하다.

2.3.1. 예제 2: Todo

/* 전체 영역 설정 */
.container {
  max-width: 400px;
  margin: 50px auto;
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
}

/* 입력창과 버튼 가로 배치 */
.input-box {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

/* 입력창 크기 확장 */
.input-field {
  flex: 1;
  padding: 10px;
}

/* 추가 버튼 디자인 */
.add-btn {
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  cursor: pointer;
}

/* 목록 스타일 초기화 */
.list-box {
  list-style: none;
  padding: 0;
}

/* 개별 항목 디자인 */
.list-item {
  padding: 10px;
  border-bottom: 1px solid #eee;
}

3. useEffect()

컴포넌트내의 함수가 호출되는 시점을 제어하는 훅 useEffect는 컴포넌트가 화면에 나타날 때, 사라질 때, 또는 특정 값이 변할 때 실행할 코드를 정의한다.

3.1. 문법정리

상황예시
첫 렌더링 시 실행 (마운트)useEffect(() => {
console.log("마운트");
}, [])
렌더링될 때마다 실행useEffect(() => {
console.log("렌더링");
})
특정 값 변경 시 실행useEffect(() => {
console.log(값);
}, [값])
컴포넌트 제거 시 정리 (언마운트)useEffect(() => {
console.log("마운트");
return () => console.log("언마운트");
}, [])
값 변경 시 실행 + 이전 것 정리useEffect(() => {
console.log(값);
return () => console.log("정리");
}, [값])

3.1.1. 마운트시

컴포넌트가 화면에 처음 나타날 때 단 한 번 실행된다. 빈 배열 []을 의존성 배열로 전달한다.

useEffect(() => {
  console.log("컴포넌트가 화면에 나타남");
}, []);

3.1.2. 렌더링시

의존성 배열을 생략하면 렌더링될 때마다 실행된다. 상태나 props가 바뀔 때마다 매번 호출되므로 주의해서 사용한다.

useEffect(() => {
  console.log("렌더링됨");
});

3.1.3. 특정값 변경시

의존성 배열에 값을 넣으면 그 값이 바뀔 때마다 실행된다.

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

useEffect(() => {
  console.log("count가 바뀜:", count);
}, [count]);

3.1.4. 언마운트시

return으로 **정리 함수(cleanup)**를 반환하면 컴포넌트가 화면에서 사라질 때 실행된다. 타이머, 이벤트 리스너 등 정리가 필요한 경우에 사용한다.

useEffect(() => {
  console.log("마운트");

  return () => {
    console.log("언마운트 - 정리 실행");
  };
}, []);

3.2. 실습: 로그인

웹브라우저의 데이터 저장 공간인 로컬 스토리지에 로그인 정보를 저장하는 로그인 페이지를 만들어보자



.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
}


.card {
  background: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
  border-radius: 10px;
  padding: 2rem;
  margin: 2rem auto;
  width: 90%;
  max-width: 40rem;
  text-align: center;
}

.control {
  margin: 1rem 0;
  display: flex;
  flex-direction: column;
  text-align: left;
}

.control label {
  font-weight: bold;
  margin-bottom: 0.5rem;
}

.control input {
  font: inherit;
  padding: 0.5rem;
  border-radius: 6px;
  border: 1px solid #ccc;
}

.actions {
  text-align: center;
  margin-top: 1rem;
}

.btn {
  font: inherit;
  background: #7a0141;
  border: 1px solid #7a0141;
  color: white;
  padding: 0.75rem 2rem;
  border-radius: 30px;
  cursor: pointer;
}

.btn:disabled {
  background: #ccc;
  border-color: #ccc;
  color: #666;
  cursor: not-allowed;
}

.btn:hover:not(:disabled) {
  background: #a40256;
  border-color: #a40256;
}


3.3. 코드 분석

3.3.1. 상태(State) 선언

const [isLoggedIn, setIsLoggedIn] = useState(false);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
변수초기값역할
isLoggedInfalse로그인 여부 — true면 홈 화면, false면 로그인 화면
email""이메일 입력창의 현재 값
password""비밀번호 입력창의 현재 값

3.3.2. useEffect — 재방문 체크

useEffect(() => {
  const storedLoginInfo = localStorage.getItem("isLoggedIn");
  if (storedLoginInfo === "1") {
    setIsLoggedIn(true);
  }
}, []);
  • localStorage는 브라우저에 데이터를 저장하는 공간이다. 새로고침해도 사라지지 않는다.
  • getItem("isLoggedIn")으로 이전에 저장된 로그인 정보를 꺼낸다.
  • 값이 "1"이면 이미 로그인한 사용자이므로 setIsLoggedIn(true)로 상태를 바꾼다.
  • 의존성 배열이 []이므로 처음 마운트될 때 한 번만 실행된다 → 무한 루프 없음.

3.3.3. loginHandler — 로그인 처리

const loginHandler = (e) => {
  e.preventDefault();
  localStorage.setItem("isLoggedIn", "1");
  setIsLoggedIn(true);
};
  • e.preventDefault(): 폼 제출 시 페이지가 새로고침되는 기본 동작을 막는다.
  • localStorage.setItem("isLoggedIn", "1"): 브라우저에 로그인 정보를 저장한다. 재방문해도 로그인 상태가 유지된다.
  • setIsLoggedIn(true): 상태를 바꿔 화면을 홈으로 전환한다.

3.3.4. logoutHandler — 로그아웃 처리

const logoutHandler = () => {
  localStorage.removeItem("isLoggedIn");
  setIsLoggedIn(false);
  setEmail("");
  setPassword("");
};
  • localStorage.removeItem("isLoggedIn"): 저장된 로그인 정보를 삭제한다.
  • setIsLoggedIn(false): 상태를 바꿔 화면을 로그인 폼으로 전환한다.
  • setEmail(""), setPassword(""): 입력창을 빈 값으로 초기화한다.

3.3.5. JSX — 화면 분기

{!isLoggedIn ? (
  <로그인 폼 />
) : (
  <환영 메시지 />
)}
  • isLoggedIn이 false이면 !isLoggedIn이 true가 되어 로그인 폼을 보여준다.
  • isLoggedIn이 true이면 환영 화면을 보여준다.
  • ? : 은 삼항 연산자로, if/else를 한 줄로 표현한 것이다.

목차

  • 구문