useState 직접 구현 부분에서 질문이 있습니다.
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();
답변 1
1
안녕하세요! 질문 주셔서 감사합니다 :)
헷갈릴 수 있는 지점을 짚어주셔서 감사합니다.
먼저 해당 예제는 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 오류가 발생합니다.
해결 방법은 말씀 주신 것처럼 크게 두 가지입니다.
setCount를 바깥 스코프에 선언해서 전역에서 접근 가능하게 만들기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
8
0
css box-sizing 관련 질문
0
17
2
스니펫이 이상해요
0
14
2
npm 설치가 잘 안됐습니다. 보안 이슈인 것 같은데, 어떻게 해야 하나요?
0
9
2
VS CODE 설치 시 관리자 권한으로 해야하는지
0
13
1
Editor Component의 최적화 불가능 이슈
0
21
2
Git 버젼 상이
0
25
2
[영한님]Spring Boot 및 프로젝트 생성
0
25
1
useCallback ⊂ useMemo
0
28
2
깃허브 저장소를 어디에 첨부하셨나요?
1
31
1
코드 줄바꿈
0
36
2
nestjs 강의는 없나요??
1
35
2
스타터 저장소
1
36
1
vs code 프로그램 동기화 가능여부
0
38
1
What is Rxjs
0
24
1
라이브러리 설치 질문
0
29
2
linter 질문
0
37
2
react-fetch -2 (loading) 에러
0
38
2
수업자료 링크 접속했는데 404에러 뜹니다 ㅠ
1
40
1
클로드 회원가입 전인데 perplexity 프로
0
47
2
primitive에 onClick 이벤트가 안되는 경우
0
27
2
감정일기장 vercel 배포 후 새로 고침 시 404페이지가 뜨는 이유
0
40
2
useEffect return문
0
46
3
학습을 하고 블로그에 정리를 해도 괜찮을까요?
1
54
1





