inflearn logo
강의

Khóa học

Chia sẻ kiến thức

Học JS nâng cao qua giá gà rán

Tự triển khai useState

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

Đã giải quyết

57

taluee

2 câu hỏi đã được viết

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

Câu trả lời 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 방식으로 보완하여 업로드하였습니다.(다시 다운로드 부탁드립니다!)

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

ThemeProvider를 이용해서 NextThemeProvider를 따로 생성하여 Layout.tsx에 적용하는 이유는 뭘까요?

0

3

0

진짜화면이랑달라서못해먹겟어요먹겟어요

0

13

1

mission 09-01 을 수행할 수 없어요

0

14

1

문제점

0

13

2

Context API vs Zustand 그리고 Auth

0

20

2

순수 함수 / 순수 컴포넌트

0

18

1

css box-sizing 관련 질문

0

31

2

스니펫이 이상해요

0

31

2

npm 설치가 잘 안됐습니다. 보안 이슈인 것 같은데, 어떻게 해야 하나요?

0

30

2

VS CODE 설치 시 관리자 권한으로 해야하는지

0

26

1

Editor Component의 최적화 불가능 이슈

0

37

2

Git 버젼 상이

0

35

2

[영한님]Spring Boot 및 프로젝트 생성

0

42

2

useCallback ⊂ useMemo

0

34

2

깃허브 저장소를 어디에 첨부하셨나요?

1

38

1

코드 줄바꿈

0

39

2

nestjs 강의는 없나요??

1

38

2

스타터 저장소

1

39

1

vs code 프로그램 동기화 가능여부

0

42

1

What is Rxjs

0

28

1

라이브러리 설치 질문

0

33

2

linter 질문

0

40

2

react-fetch -2 (loading) 에러

0

42

2

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

1

55

1