티스토리 뷰

Web/FrontEnd

[React] useState의 정체? + stateType

Turtle1000 2021. 11. 28. 21:49

참고 : https://stackoverflow.com/questions/58860021/why-react-hook-usestate-uses-const-and-not-let

 

Why React Hook useState uses const and not let

The standard way to use a React useState Hook is the following: const [count, setCount] = useState(0); However this const count variable is clearly going to be reassigned to a different primitive...

stackoverflow.com

<!DOCTYPE html>
<html lang="en">
  <body>
    <div id="root"></div>
  </body>
  <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    const root = document.getElementById("root");

    const Container = () => {
      const [counter, setCounter] = React.useState(0);
      const onClick = () => {
        // setCounter(counter + 1);
        setCounter((cur) => cur + 1);
      };

      return (
        <div>
          <h3>Total clicks: {counter}</h3>
          <button onClick={onClick}>Click me</button>
        </div>
      );
    };
    ReactDOM.render(<Container />, root);
  </script>
</html>

간단하게 위와 같은 코드가 있다.

React + JSX를 사용해서 구현한 코드이며, 컴파일은 바벨을 이용해서 로컬에서 수행한다.

궁금한건 Container라는 함수가 수행될 때, useState가 있음에도 최초에 한 번만 수행되고 그 다음엔 수행되지 않는 이유이다.

먼저 참고에 링크를 걸어둔 곳에서 제공한 샘플 코드를 보자.

<!DOCTYPE html>
<html lang="en">
  <body>
    <div id="root"></div>
  </body>
  <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    // https://stackoverflow.com/questions/58860021/why-react-hook-usestate-uses-const-and-not-let
    let _state;
    let _initialized = false;
    function useState(initialValue) {
      if (!_initialized) {
        _state = initialValue;
        _initialized = true;
      }

      return [_state, (v) => (_state = v)];
    }

    function Component() {
      const [count, setCount] = useState(0);
      setCount(count + 1);
    }

    Component();
    Component();
  </script>
</html>

먼저 말해둘건 링크에도 명시되어 있지만 절대 useState 함수가 위와 같이 간단하진 않다.

계속 살펴보면, _initialized 변수를 통해 상태를 관리하는 것을 볼 수 있다. 또한 destructuring을 통해 setCount 함수에 Arrow function을 할당하고 있다.

그렇기에 상단에 useState가 계속 실행되더라도, 처음 실행된게 아니라는걸 알고 있어 두 번째부터는 전달 받은 값으로 _state를 수정해준다.

또한, 베스트 프렉티스(?)를 통해 아래와 같이 사용하도록 하는걸 본 적 있을 것이다.

// setCounter(counter + 1); 
setCounter((cur) => cur + 1);

간단하게 얘기하면 counter를 그대로 넘겨주면 Race Condition 문제가 발생할 수 있으므로 아래와 같이 전달해주게 된다.

근데 이렇게 되면 위에 있는 useState 함수 예시랑 좀 안맞는다는 생각이 들 것이다. 그래서 React에서는 내부적으로 stateType에 따라 리턴을 바꿔서 해주게 된다. 아래 코드는 공식 코드이다.

function stateType(state, action) {
    return typeof action === "function" ? action(state) : action;
}

위와 같이 setCount 함수의 인자로 함수를 전달하면 stateType 함수에서 적절히 변환해서 전달해주게 된다. 대략 예시를 들면,

let _state;
let _initialized = false;

function useState(initialValue) {
    if (!_initialized) {
        _state = initialValue;
        _initialized = true;
    }
    
    return [_state, (v) => stateType(_state, v)];
}
    
function stateType(state, action) {
    return typeof action === "function" ? action(state) : action;
}

function Component() {
    const [count, setCount] = useState(0);
    // setCount(count + 1);
    setCount((cur) => cur + 1);
}

Component();
Component();

위와 같은 모양이 되지 않을까 싶다.

'Web > FrontEnd' 카테고리의 다른 글

react-router-dom v6 generic 미지원  (1) 2022.01.27
[JS] 문자를 숫자로 간단하게 바꾸기  (0) 2021.12.19
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함