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

83

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에 들어간 뒤 버튼을 클릭하면, 브라우저가 이 문자열을 자바스크립트 코드처럼 실행합니다.

이때 setCount를 Counter 함수 내부의 지역 변수로 찾는 것이 아니라, 전역(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 방식으로 보완하여 업로드하였습니다.(다시 다운로드 부탁드립니다!)

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

10월 15일 삭제예정 강의 문의

0

37

1

강의제목에 10/15일 삭제라고 나와있는데,

0

48

1

[해결됨]마지막 강의 내용 수정 화면이 기능을 못하네요.

0

49

1

[해결됨]부분적으로 화면 이동이 안되는 부분이 있습니다.

0

85

6

8-2. 단항 연산자 중복 : 전위 ++ 연산자 작성 질문

0

55

1

수업 200% 완강했습니다. 추가로 요청 드립니다.

0

58

1

자료

0

41

1

소스파일

0

44

1

스크립트 영상 미일치

0

76

3

감정일기장 다이어리 필터 적용할때 컨텍스트를 Home에서 가져오는 특별한 이유가 궁금합니다.

0

58

2

강의 설명 중에 헷갈리는 것이 있네요

0

58

1

수업자료 관련 문의

0

66

3

1강 동영상 재생 오류

1

67

2

스테이징 파일들 커밋 시 오류 메시지

0

75

3

Composition단계에서 `Layer`는 누가 만드는지

0

44

1

fieldInjectionTest() 질문

0

55

1

AutoAppConfig의 존재이유

0

49

1

AppConfig와 스프링 빈 질문

0

52

1

15분 35초즈음 나오는 500개 단위로 쪼개는 경우 스레드 질문

0

37

1

Strict Mode 예시 질문!

0

58

2

수업이 안보여요

0

64

1

node 실행 오류

0

71

2

저자 블로그에 있는 강의는 어떤 강의인가요?

1

62

1

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

1

77

1