inflearn logo
강의

Course

Instructor

Advanced JS Learned Through Chicken Prices

Implementing useState from scratch

useState 직접 구현 부분에서 질문이 있습니다.

Resolved

47

taluee

2 asked

1

setCount가 전역변수에 없으면 setCount is not defined; 오류가 발생합니다.
Codex가 Counter()는 문자열을 반환하고 setCount는 Counter의 지역변수라서 브라우저가 setCount를 전역에서 찾기 때문에 나타나는 오류라고 합니다. <--이부분이 어렵습니다.
아래처럼 변경하거나 addEventListener의 콜백으로 구현하라고 하네요.

const states = [];
    let cursor = 0;
    let setCount;

    function useState(initialValue) {
      const index = cursor;
      cursor++;

      if (states[index] === undefined) {
        states[index] = initialValue;
      }

      const setState = (newValue) => {
        states[index] = newValue;
        cursor = 0;
        render();
      };

      return [states[index], setState];
    }

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

      return `<button onClick="setCount(${count + 1})">${count}</button>`;
    }

    function render() {
      const root = document.querySelector("#root");
      cursor = 0;
      root.innerHTML = Counter();
    }

    render();

 

javascript 웹앱 함수형-프로그래밍 es6 객체지향 react.js vanilla-javascript

Answer 1

1

potatosam

안녕하세요! 질문 주셔서 감사합니다 :)

헷갈릴 수 있는 지점을 짚어주셔서 감사합니다.

먼저 해당 예제는 useState의 내부 아이디어를 가장 단순하게 보여주기 위한 개념 설명용 수도코드에 가까운 예제였습니다.
즉, “상태를 외부에 저장하고, setter가 상태를 바꾼 뒤 다시 render를 호출한다”는 흐름을 보여주는 데 초점을 둔 코드입니다.

다만 말씀해주신 것처럼, 이 코드를 브라우저에서 그대로 실행하면 setCount is not defined 오류가 발생할 수 있습니다.

문제는 이 부분입니다.


return `<button onclick="setCount(${count + 1})">${count}</button>`;

onclick="setCount(...)"는 HTML 문자열 안에 들어간 인라인 이벤트 핸들러입니다.

innerHTML로 DOM에 들어간 뒤 버튼을 클릭하면, 브라우저가 이 문자열을 자바스크립트 코드처럼 실행합니다.

이때 setCountCounter 함수 내부의 지역 변수로 찾는 것이 아니라, 전역(window) 스코프에서 찾게 됩니다.

그런데 setCount는 아래처럼 Counter 함수 안에서 만들어진 지역 변수입니다.

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

그래서 클릭 시점에 브라우저가 window.setCount를 찾다 못 찾아 setCount is not defined 오류가 발생합니다.

해결 방법은 말씀 주신 것처럼 크게 두 가지입니다.

  1. setCount를 바깥 스코프에 선언해서 전역에서 접근 가능하게 만들기

  2. addEventListener로 이벤트 핸들러를 직접 연결하기



인라인 문자열 핸들러의 전역 스코프 문제를 피할 수 있고, 이벤트 콜백이 setCount를 클로저로 기억하기 때문에 addEventListener방식을 이용하는게 더 자연스러워 보입니다. ㅎㅎ

예를 들면 다음처럼 바꿀 수 있습니다.

// 전역 변수로 상태 저장 시도
let _state;

function useState(initialValue) {
  if (_state === undefined) {
    _state = initialValue;
  }

  const setState = (newValue) => {
    _state = newValue;
    render();
  };

  return [_state, setState];
}

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

  const root = document.querySelector("#root");

  root.innerHTML = `<button id="btn">${count}</button>`;

  root.querySelector("#btn").addEventListener("click", () => {
    setCount(count + 1);
  });
}

function render() {
  Counter();
}

render();

개념 설명을 위해 단순화하다 보니, 실행 환경의 스코프 문제를 고려하지 못했네요 ㅠㅠ

강의 자료도 addEventListener 방식으로 보완하여 업로드하였습니다.(다시 다운로드 부탁드립니다!)

좋은 질문 주셔서 감사합니다. :)

소스코드 제공여부

0

10

2

선생님 공유해주신 핸드북에 링크가 몇개 잘못되었어요

0

13

2

62강 실습자료가 잘못되었습니다.

0

13

1

코드 자료는 없는걸까요?

0

21

2

기본 파일 구조

0

22

2

강의 화면이 안나와요

0

29

0

강의 목표

0

33

1

중급 과정 학습 중 복습과 진도 진행의 우선순위에 대해 질문드립니다

0

34

1

빠져나오기 위해서 System.in을 닫는다는게 무슨 의민가요??

0

30

1

supabase 인증페이지로 넘어가지 않습니다

0

56

2

강의 노트 위주로 학습

0

34

1

문제2번

0

41

1

claude 설치화면과 코딩내용미 표시 문의

0

62

2

쿠키 생성 관련

0

64

3

클로드 코드 설치 후 실행이 되지 않습니다

0

52

1

클로드 코드 실행 시 반복적으로 출력되는 메세지가 있습니다

0

60

2

JWT auth error invalid token

0

59

2

43강 강의내용 질문입니다.

0

52

1

경력기술서는 어떤 방향이 좋을까요?

0

52

2

강의를 듣다보니 궁금한 부분이 있습니다.

0

63

2

중복 코드와 유지보수성 사이에서 어떤 기준으로 리팩토링해야 할지 궁금합니다

0

35

1

static 변수를 호출할때 인스턴스변수 호출하듯이 호출해도 되나요?

0

50

1

AI에게 권한 부여하기

0

60

2

학습을 하고 블로그에 정리를 해도 괜찮을까요?

1

46

1