WEB FE Repository/React

State, 리렌더링, 리액트 훅과 커스텀 훅 - 리액트의 핵심 기능

조금씩 차근차근 2025. 9. 19. 16:31

리액트에서의 State

  • 모든 컴포넌트들은 State를 가질 수 있다.
  • 현재 State에 따라 렌더링 결과를 다르게 할 수 있다.
  • State의 변화에 따라 렌더링을 다시 하는것을 Re-Rendering이라고 한다.
  • 리액트는 변수의 값의 변화로는 리렌더링 되지 않고(버퍼에 담김), State가 변화해야만 즉각적으로 리렌더링을 수행한다.
  • “react” 에서 useState를 import 하는것으로 State를 갖게 할 수 있다.
    • 이때, “react”에는 useState만 있는것이 아니므로 다음과 같이 코드를 작성해야 한다
    • import { useState } from "react";
  • state의 구성요소
    • state는 배열, useState() 함수를 통해 얻을 수 있다.
    • state가 처음 생성됐을 땐 [ undefined, f ] 라는 값을 갖는다
      • undefined : state가 처음 생성됐을 때의 값, useState() 함수에 매개변수를 넣으면 그 값이 이 값이 된다.
      • f : state의 상태를 변화시키는 “상태변화 함수”(setter). 값을 인자로 받은 값으로 변화시킨다.
        • 해당 함수는 비동기 로 동작하기에, State값을 내부적으로 사용할 땐 useEffect를 사용하는 것이 좋다.
      • 그러므로 구조분해 할당을 통해 state 변수와 setState 함수를 따로 받는것이 좋다.
  • state 변수는 const 로 정의해도 setState를 사용하면 변경이 가능하다. → 그러므로 state 변수는 const로 정의하고, setState로만 변경하는 것이 좋다.
  • 부모로부터 받는 props의 값이 바뀌면 자식 컴포넌트는 리렌더링된다.

 

이를 통해 React에서는 꼭 필요한 부분에만 리렌더링을 수행한다.

리액트에서 리렌더링이 발생하는 경우

React는 성능 최적화를 위해 여러 개의 setState 호출을 일괄 처리(batch) 한다.

즉, setState를 호출하면 그 즉시 state가 변하는 게 아니라, React가 다음 렌더링 사이클에 반영하도록 예약한다.

따라서, 화면의 렌더링과 상태의 변경은 별개이므로, 이 "리렌더링이 발생하는 경우"를 반드시 알고 있어야 한다.

  1. 상태(State) 변경
  2. Props 변경
  3. 부모 컴포넌트가 렌더링될때
  4. Context를 사용하여 전역적인 변수가 변경되었을 때
  5. 강제업데이트 (forceUpdate())
중요하니 꼭 외워두자!

jsx에서 특정 태그에 접근하는 방법 → ref

  • 태그 안에 ref 속성 사용하기!
  • ref = {refPoint}
  • 이 속성을 이용해 해당 태그 주소 받아오면 다양한 메소드를 사용할 수 있다.

그런데, 이러한 "역참조"는 코드의 일관성을 깨뜨리므로, 어쩔 수 없는 상황에만 사용하도록 하자.

되도록이면 state로 UI를 제어하고, 정말 어쩔 수 없는 경우에만 ref를 사용하자.
코드의 흐름을 복잡하게 만들면, 이후에 읽게 될 코드를 예측하기 어렵게 만든다.

Reference 객체

  • useRef() 함수로 Reference 객체를 생성한다.
  • useState() 함수와 굉장히 유사하나, 리렌더링을 시키는 state 값과는 달리 어떠한 경우에도 리렌더링을 시키지 않는다.
  • 또한, 호출된 “해당 컴포넌트 인스턴스”만 사용할 수 있는 상수로써 값을 유지한 함수로 사용할 수 있게 한다.
  • 그대신, 컴포넌트가 렌더링하는 특정 DOM에 접근하여 렌더링하지 않는 다양한 조작이 가능해진다.
    • 특정 값을 강조하거나
    • 해당 DOM의 CSS값을 변경하거나 하는 등

예시 소스코드

// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개
import { useState, useRef } from "react";

function Register() {
  const [input, setInput] = useState({
    name: "",
    birth: "",
    country: "",
    bio: "",
  });
  function onChangeInput(e) {
    setInput({
      ...input,
      [e.target.name]: e.target.value,
    });
    console.log(e.target.name, e.target.value, input[e.target.name]);
  }
  const inputRef = useRef();

  function onSubmit(e) {
    if (input.name === "") {
      inputRef.current.focus();
    }
  }
  return (
    <>
      <div>
        <input
          ref={inputRef}
          type="text"
          name="name"
          onChange={onChangeInput}
        />
      </div>
      <div>
        <input
          type="date"
          name="birth"
          onChange={onChangeInput}
        />
      </div>
      <div>
        <select
          name="Country"
          id=""
          onChange={onChangeInput}>
          <option value="선택">---선택---</option>
          <option value="kr">한국</option>
          <option value="us">미국</option>
          <option value="uk">영국</option>
        </select>
      </div>
      <div>
        <textarea
          name="bio"
          cols="30"
          rows="10"
          onChange={onChangeInput}></textarea>
      </div>
      <button onClick={onSubmit}>submit</button>
    </>
  );
}

export default Register;
  • Ref 값에 접근 → refObj.current

리액트 훅

  • 상태와 생명주기 메서드를 사용할 수 있게 해주는 기능.
  • useState, useRef 모두 React Hooks!
  • use 라는 접두사가 붙은 함수들은 모두 리액트 Hooks
  • 호출 제약
    • 오직 함수 컴포넌트 & 커스텀 훅내부에서만 호출할 수 있으며
    • 조건문, 반복문 내부에서는 호출이 불가능함. → 서로 다른 훅들의 호출 순서가 엉망이 될 가능성
  • use라는 접두사를 이용하여 나만의 Hook도 제작 가능.
    • 나만의 훅을 기존 훅들의 조합으로 생성 가능!
    • 중복되는 리액트 훅 코드들과 복잡한 알고리즘 과정들을 간단하게 중복 코드 제거!
  • 커스텀 훅 예시
import { useState } from "react";

function useInput(params) {
  const [input, setInput] = useState(params);

  function onChange(e) {
    setInput(e.target.value);
    console.log(input);
  }
  return [input, onChange];
}

export default useInput;
  • 커스텀 훅은 일반적으로 src폴더의 hooks 디렉토리 안에 모아둔다.