오늘은 20 web Projects중 hangman을 VanillaJS 로 구현하고, Component형식으로 바꾸던 와중.
this바인딩 때문에 고생했던 기억을 이겨내고자 정리를 해보려고한다.
Code
먼저 html에서 module type으로 index.js를 받아오기로 했다.
// index.js
import App from './App.js';
const app = new App(document.querySelector('.App'));
window.addEventListener('keydown', app.handleKeyDown);
이렇게 index.js 에서 window.addEventListner를 호출하고,
'keydown' 이벤트가 일어나면. App.js의 handleKeyDown 메소드를 호출하려고 한다.
// App.js
export default class App {
constructor($app) {
...
}
...
handleKeyDown(e) {
const { answer, correctLetters, wrongLetters } = this.state;
if (e.keyCode < 65 || e.keyCode > 90) {
return;
}
const letter = e.key;
if (correctLetters.includes(letter) || wrongLetters.includes(letter)) {
this.setState({
...this.state,
Notification: true,
});
return;
}
if (answer.includes(letter)) {
this.setState({
...this.state,
correctLetters: [...this.state.correctLetters, letter],
wrongCount: wrongLetters.length,
isPopup: correctLetters.length + 1 === answer.length,
message: 'Congratulations! You won! 😃',
isNotification: false,
});
} else {
this.setState({
...this.state,
wrongLetters: [...this.state.wrongLetters, letter],
wrongCount: wrongLetters.length,
isPopup: wrongLetters.length + 1 === 5,
message: 'Unfortunately you lost. 😕',
isNotification: false,
});
}
}
이렇게 App.js에서 this.state를 쓰려하는데, this가 window를 가리켜서 this.state 가 없는 놈이 되버린 것이다.😱
이 이유가 무엇일까를 계속해서 고민해 보았다.
🤭 이유
이것의 이유는 window.addEventListener('keydown', app.handleKeyDown)을 했을 때,
addEventListener 안에서의 this 는 e.currentTarget과 같으므로 전역 객체인 window를 가리키게 된 것이다!!
👊 해결방법
해결 방법은 constructor에서 this.handleKeyDonw에 현재 App.js의 this 를 .bind 함수를 통해 바인딩 해주면 된다 ㅎ
코드는 이렇다.
export default class App {
constructor($app) {
this.state = {
isPopup: false,
message: '',
isNotification: false,
wrongLetters: [],
wrongCount: 0,
correctLetters: [],
answer: WORDS[Math.floor(Math.random() * WORDS.length)],
};
...
this.handleKeyDown = this.handleKeyDown.bind(this);
}
...
handleKeyDown(e) {
const { answer, correctLetters, wrongLetters } = this.state;
console.log(e.currentTarget);
if (e.keyCode < 65 || e.keyCode > 90) {
return;
}
const letter = e.key;
if (correctLetters.includes(letter) || wrongLetters.includes(letter)) {
this.setState({
...this.state,
Notification: true,
});
return;
}
if (answer.includes(letter)) {
this.setState({
...this.state,
correctLetters: [...this.state.correctLetters, letter],
wrongCount: wrongLetters.length,
isPopup: correctLetters.length + 1 === answer.length,
message: 'Congratulations! You won! 😃',
isNotification: false,
});
} else {
this.setState({
...this.state,
wrongLetters: [...this.state.wrongLetters, letter],
wrongCount: wrongLetters.length,
isPopup: wrongLetters.length + 1 === 5,
message: 'Unfortunately you lost. 😕',
isNotification: false,
});
}
}
'javascript' 카테고리의 다른 글
💪REST API 설계 원칙 (0) | 2022.09.28 |
---|---|
[JavaScript] JavaScript 로 TDD 및 테스트 코드 작성 하기 (cypress) (0) | 2022.08.15 |
JavaScript로 알고리즘 준비하기(1) - 정규 표현식(문자열 갖고놀기) (0) | 2022.04.14 |