사내 레거시 코드를 개선하던 중 발생한 트러블 슈팅 내용입니다.
B2B 페이지의 상품 등록 및 수정 페이지를 리팩토링하면서 발생.
ProductForm
의 로직과 UI를 분리하기 위해 UI를 컴포넌트 단위로 수정했습니다.
UI 컴포넌트에 props
로 state
를 변경하는 setProduct
라는 함수를 Container
에서 넘겨줍니다.
UI 컴포넌트에서는 받은 props
를 사용할 때 아래 사진과 같은 에러 발생 !!
JS에서 this
는 함수를 호출하는 방식에 따라 그 값이 결정됩니다. 객체의 메서드로 함수를 호출하면, this
는 그 객체를 가리킵니다. 하지만, 단순히 함수로 호출하면, this
는 전역 객체(브라우저에서는 window
, Node.js
에서는 global
)를 가리키거나, 엄격 모드('use strict
')에서는 undefined
가 됩니다.
JS 클래스 컴포넌트 내의 메서드는 기본적으로 그 컴포넌트 인스턴스에 바인딩되지 않습니다. 따라서, 컴포넌트의 메서드를 다른 컴포넌트의 prop
으로 전달하거나, 이벤트 핸들러로 설정할 때, 그 메서드 내부에서 this
를 사용하면, this
는 컴포넌트 인스턴스를 가리키지 않게 됩니다. 이는 this.state
나 this.setState
같은 컴포넌트의 state
에 접근하려 할 때 문제를 일으킵니다.
이 문제를 해결하기 위한 방법 중 하나는 생성자(constructor
) 내에서 메서드를 컴포넌트 인스턴스에 명시적으로 바인딩하는 것입니다. 이를 통해, 메서드가 어디서 호출되든 간에 this
가 항상 해당 컴포넌트 인스턴스를 가리키도록 할 수 있습니다.
constructor(props) {
super(props);
this.setProduct = this.setProduct.bind(this);
}
이 코드는 setProduct
메서드 내의 this
가 항상 해당 컴포넌트 인스턴스를 가리키도록 보장합니다. 그래서 this.state
나 this.setState
와 같은 state
관련 작업을 안전하게 수행할 수 있게 됩니다.
클래스 문법을 사용하여 메서드를 화살표 함수로 선언하는 것은 this
가 인스턴스를 가리키게 하는 또 다른 방법입니다. 이 방식을 사용하면, 생성자에서 메서드를 바인딩할 필요가 없습니다.
setProduct = () => {
// 이곳에서의 this는 컴포넌트 인스턴스를 가리킵니다.
}
이 방법은 코드를 좀 더 간결하게 만들어주며, 바인딩을 잊어버려서 발생할 수 있는 버그를 예방해 줍니다.
현재는
setProduct
를 사용하지 않고productInput
컴포넌트를 활용하는 방식으로 수정했습니다.