Skip to content

기술 공유 react useState

ChangMyeong Lee edited this page Dec 18, 2022 · 1 revision

useState

컴포넌트 내부에서 특정 토픽의 데이터를 관리해주어야 하고, 해당 데이터가 바뀔 때마다 그에 맞게 재렌더링이 필요할 때, 이를 사용할 수 있다.

import {useState} from "react";

const Component = () => {
	// in JS
	const [state,setState] = useState(initValue);
	// in TS
	const [state,setState] = useState<typeOfState>(initValue);
	return <></>;
};

useState 를 호출하면 이에 대한 반환으로 상태값과 해당 상태값을 변화시키는 함수를 반환한다. 따라서 보통 위와 같이 구조 분해 할당으로 받아준다.

아래는 개인적인 의문을 해결하기 위해 시도한 여러 실험의 결과이다.

  1. useState 를 사용하지 않은 컴포넌트 내 변수?

    컴포넌트 내 변수를 state로 관리해주지 않더라도 컴포넌트는 잘 작동한다. 다만, 후에 해당 값이 바뀌게 되더라도(ex. 사용자와의 상호작용을 통한 값의 변경) 브라우저 측 변수의 값은 바뀌어도 해당 값이 이용되어 화면의 상태가 변하지는 않는다.(재렌더링 되지 않음)

  2. 컴포넌트 내 재렌더링의 기준?

    컴포넌트가 재렌더링 될 때, 컴포넌트 함수의 코드 블록에 있는 모든 코드가 재 실행되는데(return 내 코드를 포함한 전부), 컴포넌트가 다시 그려지는 경우(재렌더링)는 크게 다음과 같다.

    • 리액트 개발 모드를 사용할 경우(초기 렌더링된 후 자동으로 재렌더링 처리)
    • 컴포넌트 내 상태가 setState 함수를 통해 변했을 때(만약 해당 상태가 렌더링에 사용되지 않더라도(화면에 출력되지 않더라도) 재렌더링됨)
    • 상위 컴포넌트가 재렌더링될 때(만약 해당 컴포넌트에서 사용되지 않는 상위 컴포넌트의 상태의 변화가 있을 때도 일괄적으로 재렌더링)
      • 처음엔 props 값이 변할 때도 재렌더링되지 않을까 했는데, 그러진 않았음. 다만 props가 상위 컴포넌트의 상태로 관리될 경우, 상태가 변경되면 어차피 해당 클라이언트부터 주욱 재렌더링되기 때문에 그렇게 착각할 수 있음.
  3. 재렌더링될 때 state값은 왜 초기화되지 않는지?

    컴포넌트의 state 값은 React 내의 state 배열의 원소로서 관리되고, useState가 처음 선언될 때마다 그에 상응하는 커서를 생성하고 해당 커서를 인덱스 값으로 이용하여 state 배열에서 값을 찾게 된다. 쉽게 말해 state값은 컴포넌트에 종속된 값이 아닌 react 모듈 내 렉시컬 스코프의 변수를 참조해서 가져오는 것이다.(클로저) 따라서 처음 useState가 사용되었을 때(초기 렌더링)는 값을 react 모듈 내 변수로 선언해주고, 이후 렌더링부터는 그 변수를 그대로 참조해서 가져오는 것이다. 즉 useState함수는 렌더링될 때마다 실행되지만 함수 내부적 처리를 통해 안그렇게 보이도록 설계되어있는 것이다. (참고:https://seokzin.tistory.com/entry/React-useState%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%99%80-%ED%81%B4%EB%A1%9C%EC%A0%80)

  4. setState 함수의 함수형 인자

    setState의 인자는 값과 함수를 모두 받을 수 있다. 둘의 차이라고 하면, 만약 값으로 인자를 받을 경우, 상태가 변경되어 재렌더링이 이루어지고 useState를 통해서 바뀐 값을 다시 가져오고 나서야 바뀐 상태값을 이용할 수 있다. 만약 함수를 인자로 받을 경우엔 setState가 호출된 이후 곧바로 바뀐 값을 사용할 수 있게된다. 따라서 useEffect와 같은 훅에서 상태를 변경시킨 후 이 값을 바로 사용하기 위해서는 함수로 상태를 넘겨주어야 한다.

  5. 연속된 setState 호출 시 가장 마지막 호출만 적용되는 현상

    이는 setState 인자에 값을 할당했을 때 나타나는 현상인데, 이것이 발생하는 이유는 setState가 비동기 방식으로 작동하기 때문이다. setState가 수행하는 작업은 state값을 수정하고 재렌더링 시키는데, 만약 이것이 동기적으로 작동한다면 재렌더링이 굉장히 자주 발생하여 성능 상에 문제가 발생할 것이다. 따라서 리액트는 이를 비동기로 처리하는데, 이 때 연속된 변경 사항들을 하나로 통합하여 처리하게 된다. 이 때 만약 인자로 값을 주었다면 변경 사항들을 통합하는 과정에서 마지막 변경만 살아남게 된다. 이를 해결하기 위해서는 인자로 함수를 주면 된다. 이렇게 주더라도 setState가 호출된 후 콘솔을 찍어보면 그대로이지만(비동기로 처리되는 것은 동일하기 때문) 최소 다음 렌더링 때 연속된 변경 사항들이 모두 적용시킬 수 있다.

    import {useState} from "react";
    
    const [count,setCount] = useState(0);
    
    // 값으로 state 변경
    setCount(count+1);
    // 함수로 state 변경
    setCount((count)=>count+1);
  6. setState를 통해 같은 값을 주었을 때

    import {useState} from "react";
    
    const Component = ()=>{
    	console.log("코드 실행");
    	const [state,setState] = useState(0);
    	return <div onClick={()=>setState(1)}>{"버튼"}</div>;
    }

    만약 위와 같은 컴포넌트가 있다면 버튼을 여러 번 클릭 했을 때 어떤 식으로 콘솔이 찍힐까. 정답은 몇번을 클릭하든 “코드 실행”이 3번 찍힌다. 우선 처음 렌더링할 때 콘솔이 한번 찍히며, 그 다음 state가 0→1로 변경되어 재렌더링 될 때 한번 찍힌다. 그리고 마지막 state가 1→1이 될 때 한번 찍힌다. 이 때 콘솔은 3번 찍히지만 실제로 렌더링은 2번만 일어난다고 한다. 즉, 같은 값이 들어간 순간 코드 블럭의 코드들이 실행되기는 하지만 이미 그 때부터 렌더링은 진행되지 않는다.

Clone this wiki locally