카카오클라우드 AIaaS 교육/클라우드 어플리케이션 개발

[스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY 34 - react

mangji2 2025. 5. 19. 16:11

 

Hook은 함수형 컴포넌트에서도 상태 관리와 생명주기 기능을 사용할 수 있도록 해주는 기능이다.

React의 Hook들을 하나씩 상세하게 정리해보려고 한다.

 

● 우선 리액트 Hook이란?

  • 함수형 컴포넌트에서 상태라이프사이클을 관리할 수 있게 해주는 기능
  • 주요 포인트
  • useState로 상태 관리
  • useEffect로 라이프사이클 제어
  • useMemo,UseCallback으로 성능 최적화
  • useContext,useReducer 등 다양한 Hook 사용 가능

 

● State란?

state는 컴포넌트가 가지고 있는 동적인 데이터
사용자 인터랙션, 네트워크 응답 등으로 인해 바뀔 수 있는 값을 저장해두는 React 내부의 기억 장소이다

 

예를 들어서

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

 

  • count라는 상태를 만들고
  • setCount를 통해 상태를 변경하면
  • 컴포넌트는 자동으로 리렌더링돼서 바뀐 값을 화면에 보여주는 로직이다.

 

● LifeCycle이란?

 

lifecycle은 컴포넌트가 생겨나고(render), 업데이트되며, 사라지는전 과정의 흐름을 말한다.

단계 설명 예시
Mount 컴포넌트가 처음 화면에 나타남 API 호출, 초기 설정
update 상태 또는 props 변경으로 컴포넌트가 다시 렌더링 count가 바뀔 때
Unmount 컴포넌트가 사라질 때 타이머 정리,이벤트 해제

 

예를 들어서

useEffect(() => {
  console.log("마운트 or 업데이트 됨");

  return () => {
    console.log("언마운트 됨");
  };
}, []);

 

  • 마지막에 붙는 [] 배열을 의존성 배열이라고 한다
  • 이 배열 안에 있는 값이 변경될 때만 useEffect를 다시 실행해준다.
  • 컴포넌트가 마운트됨 → "마운트 or 업데이트 됨" 출력됨
  • 컴포넌트가 언마운트됨 → "언마운트 됨" 출력됨

 

 

이제 hook과 state,lifecycle의 개념을 이해했으니 Hook을 더 자세하게 공부해 보도록 하겠다.

 

[9] 필수 리액트 Hook(훅)

🧩 1. useState – 상태(state) 저장하기

정의

컴포넌트 내부에서 상태 값을 선언하고 관리할 수 있게 해주는 Hook.
렌더링을 유발하며, 함수형 컴포넌트에서 가장 자주 사용된다.

함수 컴포넌트에서는 state라는 것을 제공하지 않기 때문에 useState() 훅을 사용해야함

문법

const [state, setState] = useState(initialValue);
  • 첫 번째: 현재 상태값
  • 두 번째: 첫 번째 상태를 업데이트하는 함수
  • 상태를 직접 수정하는 것이 아니라, 상태 업데이트 함수를 호출하여 상태를 변경한다.
  • 이렇게 초깃값을 넣어 호출하면 return값 ==> 배열 나옴

예제

import React, { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0); // count,setCount : getter,setter 개념으로 이해했음

  const increment = () => {
    // 잘못된 예시
    count = count + 1;

    // 올바른 예시
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

 

★ 그런데 여기서 setCount 함수가 count를 증가시켜주는데 그럼 useState의 역할이 뭔지 로직이 헷갈렸음

 

  • React에게 이 컴포넌트 안에 count라는 상태를 만들 건데, 초기값은 0 라고 알려줌
  • 그러면 React는 이 상태를 컴포넌트 내부적으로 저장하고 관리하기 시작한다.
  • setCount를 실행하면 React가 내부적으로 저장한 값을 변경함
  • 그리고 자동으로 컴포넌트를 다시 렌더링해줌
  •    setCount()는 단순히 값을 바꾸는 게 아니라 "렌더링 요청"까지 포함된 함수인 것이다.

 

통합적 관리코드

import React, { useState } from "react";

function App() {
  // 통합 상태 객체
  const [state, setState] = useState({
    score: 0,
    name: "Alice",
  });

  const incrementScore = () => {
    setState((prevState) => ({
      ...prevState,
      score: prevState.score + 1,
    }));
  };

  const changeName = () => {
    setState((prevState) => ({
      ...prevState,
      name: prevState.name === "Alice" ? "Bob" : "Alice",
    }));
  };

  return (
    <div>
      <h1>점수: {state.score}</h1>
      <button onClick={incrementScore}>Increase Score</button>
      <h2>이름: {state.name}</h2>
      <button onClick={changeName}>Change Name</button>
    </div>
  );
}

export default App;

특징

  • 상태 변경 시 컴포넌트가 리렌더링된다.
  • useState의 값은 비동기적으로 업데이트된다.

주의

  • 상태는 직접 변경하지 않고 반드시 setState 함수를 사용해야 한다.
  • 이전 상태를 기준으로 업데이트하려면 콜백 패턴 사용:
setCount(prev => prev + 1);

🧩 2. useEffect – 부수효과 처리 (데이터 fetch, 타이머 등)

정의

- 컴포넌트가 렌더링된 이후 또는 특정 상태가 변경될 때,
부수효과(side effect) 를 수행할 수 있도록 도와주는 Hook.

- 컴포넌트 생명주기 함수인componentDidMount(), componentDidUpdate(), componentWillUnmount 와 동일한 기능을 하나로 통합해서 제공

문법

useEffect(() => { // 실행 코드 return () => { // 클린업 코드 (옵션) }; }, [dependencies]);

예제

// componentDidMount, componentDidUpdate 를 대체합니다.
💫 처음 렌더링 될 때 + 리렌더링 될 때마다 실행
useEffect(() => {
	console.log('useEffect 함수실행')
});
=> onChange 이벤트에 setState걸어서 확인해보기

💫 처음 렌더링 될 때만 실행
useEffect(() => {
	console.log('useEffect 함수실행')
}, []);

💫 처음 렌더링 될 때 + 대괄호 안 값이 변할 때 실행
useEffect(() => {
	console.log('useEffect 함수실행')
}, [state]);


// componentWillUnmount 를 대체합니다.
💫 useEffect에서 리턴하는 함수는 컴포넌트 언마운트시 호출됨
useEffect(() => {
	console.log('useEffect 함수실행')
	return() => {
		// clean up 코드 작성
		console.log('컴포넌트가 화면에서 사라질 때 실행 (자식컴포넌트가 부모컴포넌트에서 사라질 때 )');
  }
}, []);

ex)
useEffect(()=> {
    const time = setInterval(() => {
        console.log('반복반복 setInterval')
    }, 1000)

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

함수형 컴포넌트 예제

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

특징

  • [] 의존성 배열이 비어 있으면 컴포넌트 마운트 시 1회만 실행된다.
  • 반환 함수는 언마운트 시 클린업 용도로 실행된다.

주의

  • 무한 루프를 막으려면 의존성 배열을 정확히 설정해야 한다.
  • 상태(setState)를 useEffect 안에서 업데이트할 경우, 리렌더링이 발생한다.

 

🧩 4. useRef – DOM 접근 또는 값 기억

정의

- 렌더링 사이에도 값이 유지되며, 변경되어도 리렌더링을 유발하지 않는 mutable 객체를 반환한다.
주로 DOM 참조 또는 이전 값 저장에 사용된다.

- 특정 컴포넌트에 접근할 수 있는 객체를 의미한다.

문법

const ref = useRef(initialValue);

예제: 

import React, { useRef, useState } from "react";

function App() {
  const countRef = useRef(0);
  const [renderCount, setRenderCount] = useState(0);

  console.log("렌더링");

  const increment = () => {
    // 값을 바꿔도 렌더링이 일어나지 않음
    countRef.current++;
    console.log(`Count (useRef): ${countRef.current}`);
  };

  const triggerRender = () => {
    setRenderCount(renderCount + 1);
  };

  return (
    <div>
      <p>Render Count: {renderCount}</p>
      <button onClick={increment}>Increment useRef Count</button>
      <button onClick={triggerRender}>Trigger Re-render</button>
    </div>
  );
}

export default App;
 

특징

  • .current 속성을 통해 값을 읽고 쓸 수 있다.
  • 값이 바뀌어도 컴포넌트는 리렌더링되지 않는다.
  • 렌더링에 영향을 주지 않으면서 값을 저장하고 싶을 때 사용

변수,state,useRef의 차이

1. 변수 (let, const) – 함수 실행 중 잠깐 쓰는 값

특징

  • 일반적인 자바스크립트 변수
  • 컴포넌트 함수가 실행될 때마다 초기화됨
  • 값이 바뀌어도 렌더링에 영향을 주지 않음

2. useState – 값 저장 + 렌더링까지 자동

특징

  • React의 상태(state) 관리 도구
  • 값이 바뀌면 컴포넌트가 자동으로 리렌더링
  • 렌더링이 일어나도 이전 값을 유지한다.

3. useRef – 렌더링 안 일어나고 값은 기억됨

특징

  • 값을 저장하되, 렌더링은 유발하지 않음
  • .current 속성에 저장됨
  • 렌더링 사이에서도 값 유지
  • DOM 요소 참조 or 내부적으로 값 저장할 때 유용하다.

🧩 5. useMemo – 값 메모이제이션 (계산 최적화)

정의

- 계산 비용이 큰 연산의 결과를 메모이제이션(기억) 하여,
의존성 값이 변경될 때만 다시 계산한다.

문법

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • 의존성 배열에 있는 값이 바뀔때만 다시 계산한다.
  • 계산된 결과가 저장되는 변수, 즉 캐시된 값 == memoizedValue

 

예제 : useMemo를 통해 최적화 구현해보기

import React, { useState, useMemo } from "react";

function App() {
  const [number, setNumber] = useState(5);
  const [text, setText] = useState("");

  // 복잡한 계산을 수행하는 함수
  const computeFactorial = (n) => {
    console.log("Computing factorial...");
    if (n <= 0) return 1;
    return n * computeFactorial(n - 1);
  };

  // 1. useMemo를 사용하지 않은 경우
  const factorialWithoutMemo = computeFactorial(number);

  // 2. useMemo를 사용한 경우
  const factorialWithMemo = useMemo(() => computeFactorial(number), [number]);

  return (
    <div>
      <h1>Factorial Calculator</h1>

      <p>
        <strong>Without useMemo:</strong> Factorial of {number} is:{" "}
        {factorialWithoutMemo}
      </p>

      <p>
        <strong>With useMemo:</strong> Factorial of {number} is:{" "}
        {factorialWithMemo}
      </p>

      <button onClick={() => setNumber(number + 1)}>Increment Number</button>

      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Type something..."
      />
    </div>
  );
}

export default App;

 

특징

  • 렌더링 최적화를 위해 불필요한 연산 방지
  • 반드시 의존성 배열을 정확히 지정해야 한다

🧩 6. useCallback – 함수 메모이제이션

정의

- 함수를 메모이제이션하여 의존성 값이 바뀔 때만 새 함수를 생성하고,
그 외에는 이전 함수를 그대로 재사용한다.

- useCallback() 훅에서 파라미터로 받는 함수를 콜백이라고 부른다.

- 의존성 배열에 있는 변수 중 하나라도 변경되면 메모이제이션된 콜백함수를 반환한다.

문법

const memoizedCallback = useCallback(
  () => {
    doSomething(의존성 변수1, 의존성 변수2);
  },
  [의존성 변수1, 의존성 변수2],
);

 

  • memo대신 이 hook을 쓰는 이유는?
  • react에서 자식 컴포넌트에게 함수를 props로 넘길 때, 함수가 매번 새로 만들어지면
  • 자식이 불필요하게 리렌더링될 수 있기 때문이다.

예제

import React, { useEffect, useState, useCallback } from "react";

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

  // 해당 함수가 메모이제이션되어 의존성배열에 추가한 값이 바뀔 때만 함수가 호출된다.
  const getCount = useCallback(() => {
    console.log("getCount:", count);
    return;
  }, []);

  useEffect(() => {
    console.log("getCount 함수가 변경될 때 호출");
  }, [getCount]);

  return (
    <div>
      <p>Count: {count}</p>

      <button onClick={() => setCount((prev) => prev + 1)}>증가</button>

      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Type something..."
      />
    </div>
  );
}

export default App;

 

특징

  • 자식 컴포넌트에 props로 함수를 넘길 때 렌더링 최적화에 유용
  • React.memo() 와 함께 사용하면 효과 극대화
  • 자식컴포넌트에 props가 변하면 리렌더링됨

 


본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 (B-log) 리뷰로 작성 되었습니다.