Type something to search...

1. Hook

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

1.1. Hook 사용 규칙

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

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

1.2. 자주 쓰는 Hook 목록

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

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

2. UseState()

2.1. State란?

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

2.1.1. 기본 사용법

1
import { useState } from "react";
2
3
function App() {
4
const [count, setCount] = useState(0);
5
6
return (
7
<div>
8
<p>횟수: {count}</p>
9
<button onClick={() => setCount(count + 1)}>증가</button>
10
</div>
11
);
12
}

2.2. useState 동작 원리

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

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

2.2.1. 예제: 카운터

1
function Counter() {
2
const [num, setNum] = useState(0);
3
4
const plus = () => setNum(num + 1);
5
const minus = () => setNum(num - 1);
6
7
return (
8
<div>
9
<h2>{num}</h2>
10
<button onClick={plus}>+</button>
11
<button onClick={minus}>-</button>
12
</div>
13
);
14
}

2.3. 객체와 배열 State 관리

주의

주의: 직접 수정 금지!

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

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

...은 객체나 배열의 내용물을 꺼내서 펼치는 자바스크립트 문법이다.

2.3.0.0.0.1. 전개연산자를 사용하여 객체를 수정
1
const user = { name: "철수", age: 20 };
2
const newUser = { ...user, name: "영희" };
2.3.0.0.0.2. 전개연산자를 사용하지 않고 객체를 수정
1
const user = { name: "철수", age: 20 };
2
const newUser = { name: "영희", age: user.age };
2.3.0.0.0.3. 전개연산자를 사용하여 배열을 수정
1
const fruits = ["사과", "바나나"];
2
const newFruits = [...fruits, "오렌지"];
2.3.0.0.0.4. 전개연산자를 사용하지 않고 배열을 수정
1
const fruits = ["사과", "바나나"];
2
const newFruits2 = fruits.concat("오렌지");

2.3.1. 예제 2: Todo

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. 마운트시

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

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

3.1.2. 렌더링시

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

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

3.1.3. 특정값 변경시

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

1
const [count, setCount] = useState(0);
2
3
useEffect(() => {
4
console.log("count가 바뀜:", count);
5
}, [count]);

3.1.4. 언마운트시

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

1
useEffect(() => {
2
console.log("마운트");
3
4
return () => {
5
console.log("언마운트 - 정리 실행");
6
};
7
}, []);

3.2. 실습: 로그인

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

3.3. 코드 분석

3.3.1. 상태(State) 선언

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

3.3.2. useEffect — 재방문 체크

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

3.3.3. loginHandler — 로그인 처리

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

3.3.4. logoutHandler — 로그아웃 처리

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

3.3.5. JSX — 화면 분기

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