☁️ goormTIL | React #26

매루·2025년 10월 16일

goormTIL

목록 보기
24/67
post-thumbnail

📅 2025-10-16

➡️ React useState, useEffect, useRef에 대해 새롭게 알게 된 것 또는 헷갈리는 부분 정리


🔎 학습 리마인드

📌 useState

  • useState는 React의 가장 기본적인 hook이고, 컴포넌트에서 상태를 관리하게 해줌

기본 형태

const [state, setState] = useState(initialState); 
  • state를 변수로 사용하고, setState를 이용해서 state값을 수정할 수 있음
  • 만약에 state가 원시 데이터타입이 아닌 객체 데이터 타입인 경우 불변성을 유지해줘야 함

💡 함수형 업데이트

// 일반적인 방식
setCount(count +1);

// 함수형 업데이트
setState((prev) =>{prev +  1});
  • setState( ) 안에 업데이트 함수 내부에서 수정할 값이 아니라, 함수를 넣을 수 있음
  • 함수의 인자에서는 현재 state를 가져올 수 있고 { } 안에서는 이 값을 변경하는 코드를 작성하여 업데이트를 할 수 있음

차이

  • 일반적인 업데이트 방식은 버튼을 클릭했을 때 setNum(num + 1)의 명령이 3번이 각각 실행되는 것이 아니라, 여러번의 요청을 하나로 묶어 처리함 → 배치(batch)
    function App() {
      const [num, setNum] = useState(0);
    
      return (
        <div>
          <div>{num}</div>
          <button
            onClick={() => {
              setNum(num + 1);
              setNum(num + 1);
              setNum(num + 1);
            }}
          >
            + 버튼
          </button>
        </div>
      );
    }
  • 함수형 업데이트 방식은 이전 상태(prev)를 기준으로 새 값을 계산하기 때문에 React가 여러 요청을 순서대로 하나씩 처리
    function App() {
      const [num, setNum] = useState(0);
    
      return (
        <div>
          <div>{num}</div>
          <button
            onClick={() => {
              setNum((prev) => prev + 1);
              setNum((prev) => prev + 1);
              setNum((prev) => prev + 1);
            }}
          >
            + 버튼
          </button>
        </div>
      );
    }
  • 이는 불필요한 렌더링을 줄이고, 앱의 성능을 높이기 위함

📌 useEffect

  • 컴포넌트가 화면에 그려진 이후(렌더링 완료 후)마다 어떤 일을 수행하고 싶을 때 쓰는 hook

💡 언제 사용하나?

  • 컴포넌트가 렌더링 직후 한 번 실행하고 싶을 때
    (예: 초기 데이터 로딩)
  • 특정 값이 변할 때마다 후속 작업을 하고 싶을 때
    (예: 검생어 변경 시 api 호출)
  • 컴포넌트가 사라질 때 정리(Clean up) 작업이 필요할 때
    (예: 이벤트 해제)
import React, { useEffect } from "react";

function App() {
  useEffect(() => {
    console.log("렌더 이후 실행");
  });

  return <div>Home</div>;
}

export default App;

💡 의존성 배열

useEffect(() => {
  // 하고 싶은 작업
}, [/* 여기에 의존성 값들 */]);
  • 빈 배열([])인 경우 → 최초 1회

    useEffect(() => {
      console.log("처음 한 번만 실행");
    }, []); // mount 후 1회
    • 컴포넌트가 처음 나타난 뒤 한 번만 실행됨
    • 입력을 계속 바꿔도 다시 실행되지 않음
  • 값이 있는 경우 → 해당 값이 바뀔 때마다

    const [value, setValue] = useState("");
    
    useEffect(() => {
      console.log("value 변경 감지:", value);
    }, [value]);
    • value가 바뀔 때마다 effect가 재실행 됨

💡 컴포넌트의 생명주기와 useEffect

  • 화면에 처음 나타날 때 마운트 → 컴포넌트가 DOM에 추가되는 시점 → useEffect(() ⇒ {}, [])
  • state나 props가 바뀔 때 업데이트 → 컴포넌트가 다시 렌더링되는 시점 → useEffect(() ⇒ {}, [state])
  • 화면에서 사라질 때 언마운트 → 컴포넌트가 DOM에서 제거되는 시점 → return ( ) ⇒ {…}

💡 clean up (정리 함수)

  • 컴포넌트가 사라질 때(unmount) 실행할 정리 로직을 반환 값으로 작성
    import React, { useEffect } from "react";
    
    const App = () => {
    
    	useEffect(()=>{
    		// 화면에 컴포넌트가 나타났을(mount) 때 실행하고자 하는 함수 로직
    
    		return ()=>{
    			// 화면에서 컴포넌트가 사라졌을(unmount) 때 실행하고자 하는 함수 로직
    		}
    	}, [])
    
    	return <div>React App Page</div>
    };
    
    export default App;
    • useEffect 안에서 return을 해주고 이 부분에 실행되길 원하는 함수를 넣으면 됨

📌 useRef

💡 언제 사용하나?

  • 렌더링과 무관하게 값을 기억하고 싶을 때
  • DOM 요소에 직접 접근해야 할 때 (포커스, 스크롤)

기본 구성

import { useRef } from "react";
const ref = useRef("초기값");

기본 사용법

import { useRef } from "react";

function App() {
  const boxRef = useRef("초기값"); // { current: "초기값" }

console.log(boxRef);
  // 값 변경 (화면은 바뀌지 않음)
  boxRef.current = "업데이트된 값";

  console.log(boxRef.current); // "업데이트된 값"
  return <div>useRef 데모</div>;
}

export default App;

  • ref 값은 컴포넌트가 몇 번 렌더링되도 unmount 전까지 current유지

💡 useState vs. useRef 차이 예제

import { useRef, useState } from "react";

function App() {
  const [stateCount, setStateCount] = useState(0);
  const refCount = useRef(0);

  const incState = () => setStateCount((v) => v + 1);
  const incRef = () => {
    refCount.current += 1; // 화면엔 즉시 반영되지 않음
    console.log("refCount:", refCount.current);
  };

  return (
    <>
      <div>
        state 카운터: {stateCount}{" "}
        <button onClick={incState}>+1 (state)</button>
      </div>
      <div>
        ref 카운터(화면엔 고정): {refCount.current}{" "}
        <button onClick={incRef}>+1 (ref)</button>
      </div>
    </>
  );
}

export default App;
  • stateCount는 바뀌면 리렌더링 됩니다 → 화면이 갱신 됨
  • refCount.current는 값만 바뀝니다 → 화면 갱신 안됨 (로그로만 확인 가능)

💡 DOM 접근

  • 포커스 주기
    import { useEffect, useRef } from "react";
    
    function App() {
      const idInputRef = useRef(null);
    
      useEffect(() => {
        idInputRef.current?.focus(); // 마운트 직후 포커스
      }, []);
    
      return (
        <>
          <div>
            아이디: <input type="text" ref={idInputRef} />
          </div>
          <div>
            비밀번호: <input type="password" />
          </div>
        </>
      );
    }
    
    export default App;
    <input /> 태그에는 ref라는 속성이 있습니다. 이것을 이용해서 DOM 요소에 접근할 수 있음

실습

  • 아이디가 10자가 되면 비밀번호로 포커스 이동
    import { useEffect, useRef, useState } from 'react';
    
    function App() {
        const idRef = useRef(null);
        const pwdRef = useRef(null);
        const [id, setId] = useState('');
    
        useEffect(() => {
            idRef.current?.focus(); // 마운트 직후 포커스
        }, []);
    
        useEffect(() => {
            if (id.length >= 10) pwdRef.current?.focus();
        }, [id]);
    
        const handleLog = (e) => {
            setId(e.target.value);
        };
    
        return (
            <>
                <div>
                    아이디: <input type="text" ref={idRef} value={id} onChange={handleLog} maxLength={10} />
                </div>
    
                <div>
                    비밀번호: <input type="password" ref={pwdRef} />
                </div>
            </>
        );
    }
    
    export default App;

0개의 댓글