usestate의 업데이트는 비동기적이다?

rlorxl·2022년 11월 27일
1

React

목록 보기
3/10
post-thumbnail

useState

리액트에서 화면을 업데이트(리렌더링)하고 싶다면 특정 컴포넌트가 변경되었다는것을 알려주는 방법이 필요하다.
useState는 함수 컴포넌트 내에서 어떠한 상태와 리렌더링 되는 상태의 값을 지정해주는 hook이다.

const [title, setTitle] = useState(props.title);

  • title : 상태변수
  • setTitle : 새로운 title의 값을 설정하기 위해 호출하는 함수.

주의
state는 컴포넌트별 인스턴스를 기반으로 독립적인 state를 갖기 때문에 똑같은 컴포넌트가 여러개 있어도 다른 컴포넌트에서는 state가 변경되지 않으며 이벤트를 발생시킨 특정 컴포넌트만 재평가 된다.

단방향식 데이터 흐름
모든 state는 항상 특정한 컴포넌트가 소유하고 있으며 그 state로부터 파생된 UI 또는 데이터는 오직 트리구조에서 자신의 “아래”에 있는 컴포넌트에만 영향을 미친다.

객체 state관리

state는 하나의 컴포넌트안에서 여러개의 state를 가지고 있는 것도 가능하며, 별도의 setState()호출로 변수를 독립적으로 업데이트 할 수 있다.

하나의 state로 관리하려면 초기값을 객체로 주면 된다.

// const [title, setTitle] = useState('');
// const [amount, setAmount] = useState('');
// const [date, setDate] = useState('');

const [userInput, setUserInput] = useState({
  title: '',
  amount: '',
  date: '',
});

위와 아래는 완전히 동일하게 동작하는 코드이다.

이전state에 의존하는 state업데이트

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

  const countHandler = () => {
    setCount(count + 1);
    setCount(count + 1);
  };

  return (
    <>
      <h1>{count}</h1>
      <button onClick={countHandler}>plus</button>
    </>
  );
};

이런 코드가 있을 때 setCount는 두번 작동하지 않고 한번씩만 처리된다.

이전state에 의존하는 state를 업데이트 하려면 state를 오버라이드(덮어쓰기)하는 함수 구문을 사용해야 한다. 이때 첫번째 인자는 현재 state값을 가리킨다.

불변성 지키기

불변성을 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트 됨을 감지할 수 있고 이에 필요한 렌더링이 발생한다.
원시타입(boolean, number, string)은 이미 불변성을 가지고 있다. → 변수에 원시 타입의 값을 할당하면, 메모리에 값 자체가 저장된다.
참조타입(Object, Array)은 불변성을 가지고 있지않다. → 변수에 메모리 값이 담긴 주소가 저장된다. 참조타입은 setState를 할 때 불변성을 가지도록 호출해야 한다. (함수형 컴포넌트에서 상태를 업데이트할 때 값 자체가 대체되기 때문)

state의 업데이트는 비동기적이다.

state 업데이트는 비동기적일 수 있다.

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

  const countHandler = () => {
    setCount((count) => count + 1);
    console.log(count)
  };

  return (
    <>
      <h1>{count}</h1>
      <button onClick={countHandler}>plus</button>
    </>
  );
};

바뀐 count값을 확인하기위해 setCount를 실행하고 바로 아래에 console.log를 찍어보면 바뀐 상태값을 바로 확인할 수 없고 이전값이 뜬다.

이유는 useState가 비동기적으로 동작하기 때문인데 정확히 말하면 setState가 비동기로 동작한다.
리액트는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한번에 처리한다. (16ms동안 변경된 상태 값들을 하나로 묶어 처리한다.)

리액트는 component의 state가 변경될 때마다 component를 리렌더링 시킵니다. 하지만 setState를 할 때마다 state를 변경하고 컴포넌트를 렌더링 시킨다면 불필요한 렌더링이 너무 많아져 애플리케이션이 느려질 수도 있는 단점이 있습니다. 그렇기 때문에 리액트는 setState를 모두 모아 컴포넌트가 렌더링되기 전 한 번에 state를 갱신해주고 한 번만 컴포넌트가 렌더링하도록 되어있습니다.

때문에 업데이트된 상태값을 바로 보려면 useEffect, deps를 사용해서 state가 업데이트될 때 console.log가 실행되도록 해야한다.

const Counter = () => {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
  	console.log(count)
  },[count])

  const countHandler = () => {
    setCount((count) => count + 1);
  };

  return (
    <>
      <h1>{count}</h1>
      <button onClick={countHandler}>plus</button>
    </>
  );
};

0개의 댓글