컴포넌트를 분할하면서, 원래 render 메서드 하나로만 관리하다가 render 메서드
와 mounted 메서드
를 분리했다. render와 mounted를 분리한 이유가 뭘까?
render 안에서 mounted가 호출된다. 만약 특정 돔에 하위 컴포넌트를 추가해야 할 때 특정 돔이 만들어지지 않았을 수 있기 때문에
<div id="app"></div>
처럼 미리 존재해야할 돔을 미리 렌더링 되어야 한다. 이 과정을 render에서 하고 나중에 추가돼야할 컴포넌트는 mounted에서 렌더링 된다.
src/App.js
class App extends Component {
mounted() {
new Items($items, {
/*
filteredItems,
toggleItem: toggleItem.bind(this),
*/![](https://velog.velcdn.com/images/kim-jaemin420/post/b680d4f5-6fd4-4d50-a70e-edc8d982c752/image.png)
deleteItem: deleteItem.bind(this),
})
}
deleteItem(seq) {
const items = [...this.state.items];
items.splice(items.findIndex(item => item.seq === seq), 1);
this.setState({ items });
}
}
export default App;
여기서 deleteItem, toggleItem 메서드에 this를 바인딩해주는 이유가 뭘까?
src/components/Items.js
class Items {
setEvent() {
const { deleteItem, toggleItem } = this.props;
this.addEvent('click', '.deleteBtn', ({target}) => {
deleteItem(Number(target.closest('[data-seq]').dataset.seq));
});
}
}
export default Items;
Items 컴포넌트에서 this.props.deleteItem으로 접근 가능하다. 그리고 deleteItems 안에서는 this.state.items를 참조하고 있다.
this는 함수를 호출하는 형태에 따라 바인딩이 달라진다.
호출 방식에 따른 this
- 일반 함수처럼 호출: window
- 메소드로 호출: 메서드를 호출한 객체
- 생성자 함수 호출 : 생성자 함수가 (미래에) 생성할 인스턴스
처음 글을 읽을때, this binding을 왜 꼭 해줘야하는지 이해가 안돼서 binding 해주지 않고 this.props로 넘겨줘봤다.
이때, Items에서 호출하게 되면, deleteItem를 일반 함수 호출하듯이 호출했으므로 deleteItem 메서드 안에서 참조하는 this는 window 객체를 가리키고 있을거라고 예상했다.
src/App.js
class App {
mounted() {
new Items($items, {
deleteItem,
//...
})
}
deleteItem() {
// this???
}
}
export defualt App
class Items {
setEvent() {
const { deleteItem, toggleItem } = this.props;
this.addEvent('click', '.deleteBtn', ({target}) => {
deleteItem(Number(target.closest('[data-seq]').dataset.seq));
});
}
}
그러나 실제로 window 객체가 찍히는게 아니라 undefined
가 찍히는 것을 볼 수 있었다.
strict mode일 경우 일반 함수로 호출 시 this는 undefined가 바인딩 되는데, 따로 strict mode를 설정하지 않았는데 undefined가 되는게 이해가 가지 않았다.
알고 보니 module을 사용하면 자동으로 strict mode가 되기 때문에 this가 undefined로 잡히는 것을 알 수 있었다.
그렇다면, Items에서 일반 함수가 아닌 this.props.deleteItem()
으로 호출했을때 deleteItem 메서드
안에서의 this는 어떤 것을 가리키게 될까?
이 경우에 this는 당연히 this.props
를 가리키게 된다.
deleteItem 메서드
안에서 필요한 this는 this.props
객체가 아니라 App 생성자 함수가 만들어낸 인스턴스 객체이다. 이렇게 메서드를 어떻게 호출되냐에 따라 this가 변경되어 혼동을 준다. 또 다른 컴포넌트에서 deleteItem 메서드
를 호출시켜 App의 상태를 변경시키므로 this binding 없이는 App의 상태를 변경할 방법이 없다. 따라서 꼭 binding을 해줘야 한다는 것을 알 수 있었다.
this binding을 해주어도 함수를 내 마음대로 호출하면 어떻게 될지 궁금해졌다.
src/App.js
class App {
mounted() {
new Items($items, {
deleteItem: deleteItem.bind(this),
//...
})
}
deleteItem() {...}
}
export defualt App
src/components/Items.js
class Items {
setEvent() {
this.addEvent('click', '.deleteBtn', ({target}) => {
this.props.deleteItem(Number(target.closest('[data-seq]').dataset.seq));
});
}
}
this.props.deleteItem()
으로 호출했음에도 불구하고 bind 해준 this가 찍히는 걸 알 수 있다.