-
모던 리액트 Deep dive - 클래스, 클로져React 2024. 2. 18. 14:04
1. 클래스란?
- 특정한 객체를 만들기 위한 일종의 템플릿.
특정한 형태의 객체를 반복적으로 만들기 위해 사용되는 것이 바로 클래스.
다음은 클래스 예제이다. (우아한테크코스 로또 미션 중 일부)
1-1 정적 메서드(static)은 클래스에서 직접 호출 할 수 있다.
const { ErrorMessage } = require("./Error"); class Validate { static purchase(callback) { return (amount) => { if (Number(amount) % 1000 !== 0) { throw new Error(ErrorMessage.IS_CORRECT_AMOUNT); } if (isNaN(amount)) { throw new Error(ErrorMessage.NOT_NUMBER); } callback(amount); }; } } module.exports = Validate;
정적 메서드는 this에 접근할 수 없지만, 인스턴스를 생성하지 않아도 사용할 수 있다.
객체를 생성하지 않더라도 여러 곳에서 재사용이 가능하다.
따라서 전역에서 사용하는 유틸 함수를 정적 메서드로 많이 활용하는 편.
1-2 getter와 setter
getter란 클래스에서 무언가 값을 가져올 때 사용.
class Car { constructor(name) { this.name = name } get firstCharacter() { return this.name[0] } } const myCar = new Car('자동차') myCar.firstCharacter //자
setter란 클래스 필드에 값을 할당할 때 사용
class Car { constructor(name) { this.name = name } get firstCharacter() { return this.name[0] } set firstCharacter(char) { this.name = [char, ...this.name.slice(1)].join('') } } const myCar = new Car('자동차') myCar.firstCharacter //자 // '차'를 할당 myCar.firstCharacter = '차' console.log(myCar.firstCharacter, myCar.name) // 차, 자동차
1-3 상속
extends를 활용하면 기본 클래스를 기반으로 다양하게 파생된 클래스를 만들 수 있다.
(다음은 '김정완의 mvc패턴' 중 일부)
import { emit, on } from "../helpers.js"; const tag = "[View]"; export default class View { constructor(element) { if (!element) throw "no element"; this.element = element; this.originalDisplay = this.element.style.display || ""; return this; } show() { this.element.style.display = this.originalDisplay; return this; } }
import View from "./View.js"; import { qs } from "../helpers.js"; export default class KeywordListView extends View { constructor(element = qs("#keyword-list-view"), template = new Template()) { super(element); this.template = template; } show(data = []) { this.element.innerHTML = data.length > 0 ? this.template.getList(data) : this.template.getEmptyMessage(); super.show(); } } class Template { getEmptyMessage() { return `<div class="empty-box">추천 검색어가 없습니다</div>` } getList(data=[]) { return ` <ul class="list"> ${data.map(this._getItem).join("")} </ul> ` } _getItem({id, keyword}) { return ` <li data-keyword="${keyword}"> <span class="number">${id}</span> ${keyword} </li> ` } }
1-4 클래스와 함수의 관계
클래스가 작동하는 방식은 JS의 프로토타입을 활용하는 것이라고 볼 수 있다.
** 클래스를 이해하고 나면 클래스형 컴포넌트에 어떻게 생명주기를 구현할 수 있는지, 왜 클래스형 컴포넌트 생성을 위해 React.Component나 Reac.pureComponent를 상속하는지, 메서드가 화살표 함수와 일반 함수일 때 어떤 차이가 있는지 등을 이해할 수 있다.
2. 클로저
2-1 클로저의 정의
클로저는 함수와 함수가 선언된 어휘적 환경의 조합 - mdn
2-2 변수의 유효 범위, 스코프
전역 스코프
전역 객체는 windows, Node.js 환경에서는 global
함수 스코프
자바스크립트는 기본적으로 함수 레벨 스코프를 따른다.
2-3 클로저의 활용
var counter = 0 function handleClick() { counter ++ }
위 counter 변수는 전역에 있어서 누구나 수정할 수 있다는 큰 문제가 있음.
클로저를 활용한 코드로 변경해보자,
function counter () { var counter = 0 return { increase: function() { return ++ counter }, decrease: function() { return -- counter }, counter: function() { return counter } } }
리액트에서의 클로저
function Component() { const [state, setState] = useState() function handleClick() { // useState 호출은 위에서 끝났지만, // setState는 계속 내부의 최신값(prev)를 알고 있다. // 이는 클로저를 활용했기 때문에 가능하다. setState((prev) => prev + 1) } }
'React' 카테고리의 다른 글
언젠가는 쓸 useLayoutEffect... (useEffect vs useLayoutEffect) (0) 2024.03.03 [React] useRef는 왜 써야하는가? (0) 2024.02.25 모던 리액트 Deep Dive - 리액트 개발을 위해 꼭 알아야 할 JS (1) 2024.02.12 Funnel에서의 상태관리 고민 (0) 2024.01.30 왕초보가 작성한 토스 퍼널의 아주 기초적인 사용법 (0) 2024.01.19