useState
포스트
취소

useState

useState

useState란?

  • state의 초기값 설정
  • getter/setter 추가

useState의 특징

  • 사용자가 직접 업데이트할 수 있는 state 변수를 선언하고 관리할 수 있다.
  • 초기값을 설정할 수 있다.
  • const 키워드로 선언을 한다.
    • 잘못된 수정을 방지하기 위한 처리다.
    • 만약 const가 아니라 var나 let으로 선언하면 값이 바뀌긴 하지만 리렌더링이 일어나지는 않는다.
  • getter와 setter로 state를 관리한다.
    • 첫번째로 명시하는 인자는 getter가 된다.
    • 두번째로 명시하는 인자는 setter가 된다.
  • getter는 순수하게 변수처럼 사용한다.
  • setter의 콜백에는 기존 값과 변경될 값을 나타내게 된다.
    • setCount((val) => val + 1)처럼 사용한다.
    • val + 1이나 ++ val은 먹히지만 val ++은 동작하지 않는다.
  • 비동기로 동작한다.

사용 방법

  • useState를 import 하기
    • import { useState } from "react";
  • 초기값/getter/setter 설정하기
    • 작성 방법
      • const [변수명, set변수명] = useState(초기값);
    • 예시
      • const [count, setCount] = useState(0);
  1. 기존의 import React from “react”;에서 import React, {useState} from “react”;로 변경한다.
  2. const [val, setVal] = useState(“원하는 값”);을 선언한다.
  3. 만약 함수를 선언해서 그 안에서 값을 변경한다면 setVal(val + “XXX”);처럼 하면 된다.
    • 특징
      • useState는 배열을 반환한다.
      • val와 setVal은 그 어떤 이름을 써도 상관이 없긴 하지만
        본인의 편의나 팀간의 협력을 위해서라도 val와 setVal과 같이 쓰는 것이 좋다.
      • 만약 setVal은 사용하지 않고 val만 사용하고 싶다면 const [val] = useState(“원하는 값”)[0];처럼 사용하면 된다.
      • useState를 사용하게 된다면 this를 사용하지 않아도 된다.
      • 리액트의 useState를 통한 setXXX를 사용할 때 값이 아닌 함수로 전달할 수 있는데,
        이 때 사용되는 변수는 이전에 setXXX를 통해서 설정된 현재의 XXX의 값을 가져올 수 있다.

예시

import { useState } from "react";

const Sample = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <h1>{count}</h1>
      <button onClick={() => setCount((val) => val - 1)}>- 1</button>
      <button onClick={() => setCount((val) => val + 1)}>+ 1</button>
    </>
  );
};

export default Sample;

useState는 비동기적으로 동작한다.

  • useState는 성능 최적화를 위해서 비동기적을 동작한다.
    • 리액트는 성능을 최적화하기 위해 setState를 배치 처리한다.
      • setState 연속으로 호출하면 그 동작들을 한 번에 모아서 한꺼번에 랜더링한다.
    • 배치 (batch)
      • 리액트가 성능 향상을 위해 여러 개의 setState를 하나의 리렌더링으로 묶는 과정
      • 16ms동안 변경된 State들을 하나로 묶는다.
        • 16ms동안 동일한 setState를 아무리 실행해봤자 1번만 실행된다.
      • 동일한 State에 대해서 여러 번 setState를 실행했다면 마지막으로 실행한 setState만 적용된다.
  • 사실 useState의 setter는 콜백을 안 써도 동작한다.
    • 예시 : setCount(count + 1)
  • useState를 동기적으로 처리하려면 인자로 콜백함수를 집어넣거나 useEffect의 의존성 배열을 활용하면 된다.
  • 테스트 코드
import { useState } from "react";

const Sample = () => {
  const [count, setCount] = useState(0);
  const fun1 = () => {
    //1씩 증가한다.
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
  };
  const fun2 = () => {
    //3씩 증가한다.
    setCount((val) => val + 1);
    setCount((val) => val + 1);
    setCount((val) => val + 1);
  };
  return (
    <>
      <h1>3씩 증가시켜보자</h1>
      <h1>{count}</h1>
      <button onClick={() => fun1()}>비동기적으로 동작</button>
      <button onClick={() => fun2()}>동기적으로 동작</button>
    </>
  );
};

export default Sample;

useInput (useState 활용)

  • useState를 활용하여 유효성 검사를 할 때 많이 사용한다.

초기값 설정하기

  • 단순하게 초기값을 설정한다.
import { useState } from "react";

const useInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);
  return { value };
}

const Sample = () => {
  const birthYear = useInput(2024);

  return (
    <>
      <h1>useInput 연습하기</h1>
      <input placeholder="몇 년도에 태어나셨나요?" value={birthYear.value} />
    </>
  );
};

export default Sample;
초기값 설정 시의 성능 변경점
  • useState의 초기값을 함수로 설정해야 하는 경우가 있다.
    • 데이터베이스에서 데이터를 조회하는 경우
    • 처리해야하는 데이터의 양이 많은 경우
  • 초기값을 함수로 주게 되면 렌더링이 될 때마다 useState가 다시 호출되기 때문에 초기값을 반환하는 함수도 늘 새로 실행된다.
  • 이를 막기 위해서는 초기값을 반환하는 함수를 콜백으로 설정하면 된다.
    • 좋은 예시
      • const [value, setValue] = useState(() => 함수명([파라미터]));
    • 나쁜 예시
      • const [value, setValue] = useState(함수명([파라미터]));

값 변경하기

  • 값을 변경하는 기능을 추가한다.
import { useState } from "react";

const useInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);
  const handleInputValue = (event) => {
    setValue(event.target.value);
  }

  return { value, handleInputValue};
}

const Sample = () => {
  const birthYear = useInput(2024);

  return (
    <>
      <h1>useInput 연습하기</h1>
      <input placeholder="몇 년도에 태어나셨나요?" value={birthYear.value} onChange={birthYear.handleInputValue}/>
    </>
  );
};

export default Sample;

유효성 검사 기능 추가하기

  • 유효성 검사를 통과했을 때만 값을 변경할 수 있는 기능을 추가한다.
import { useState } from "react";

//숫자인지 확인
const isNumber = (value) => {
  return !isNaN(value)
};

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(() => initialValue);
  const handleInputValue = (event) => {
    const newValue = event.target.value;
    let isValid = false; //유효성 검증 통과 여부
    if (typeof validator === 'function') {
      isValid = validator(newValue);
    }
    if(isValid){
      setValue(newValue);
    } else {
      //후속 조치
      console.log("유효성 검사 통과 안 됨");
    }
  }

  return { value, handleInputValue};
}

const Sample = () => {
  const birthYear = useInput(2024, isNumber);

  return (
    <>
      <h1>useInput 연습하기</h1>
      <input placeholder="몇 년도에 태어나셨나요?" value={birthYear.value} onChange={birthYear.handleInputValue} />
    </>
  );
};

export default Sample;

useTabs (useState 활용)

  • 값의 전환을 쉽게 사용하기 위한 기능
  • 화면 전환 시에 유용하다.
import { useState } from "react";

const items = [
  {
    tabName: "첫번째 버튼",
    content: "첫번째 내용"
  },
  {
    tabName: "두번째 버튼",
    content: "두번째 내용"
  },
  {
    tabName: "세번째 버튼",
    content: "세번째 내용"
  }
];

const useTabs = (initialTab, allTabs) => {
  if(!allTabs || !Array.isArray(allTabs)){
      return; 
  }
  const [currentIndex, setCurrentIndex] = useState(() => initialTab);
  return {
      currentItem : allTabs[currentIndex],
      changeItem : setCurrentIndex
  };
};

const Sample = () => {
  const {currentItem, changeItem} = useTabs(0, items);

  return (
    <>
      <h1>useTabs 연습하기</h1>
      {items.map((item, index) => <button key={index} onClick={() => changeItem(index)}>{item.tabName}</button>)}
      <div>{currentItem.content}</div>
    </>
  );
};

export default Sample;
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.