첫번째 렌더링이 성공적으로 실행되었다면 componentDidMount
함수가 실행된다. setState
등의 이유로 리렌더링을 할 때에는 실행되지 않는다. 이것과 반대로 componentWillUnmount
는 컴포넌트가 제거되기 직전에 실행되는 함수이다. componentDidUpdate
는 리렌더링 후에 실행되는 함수이다.
이렇게 첫 컴포넌트의 렌더링 후, 리렌더링 후, 제거 직전에 실행되는 함수들을 통틀어 라이프사이클이라 부른다. 클래스의 라이프사이클은 다음과 같다.
constructor → render → ref →
componentDidMount
→ (setState
/props
변화 →shouldComponentUpdate
(true) → render →componentDidUpdate
) → 컴포넌트 제거(부모 컴포넌트) →componentWillUnmount
→ 소멸
componentDidMount
에서는 주로 비동기 요청을 많이 한다. 반대로 componentWillUnmount
에서는 비동기 요청 정리를 많이 한다.
componentDidMount() {
this.interval = setInterval(() => {
console.log('interval');
}, 1000);
};
첫 렌더링이 된 직후, setInterval
과 같은 비동기 요청을 해줄 경우, 컴포넌트가 제거될 때 이 요청을 따로 제거해주지 않으면 웹사이트가 종료될 때까지 비동기 요청이 계속되는 문제가 있다. 비동기 요청이 계속되면 메모리 또한 끝없이 할당되어서 큰 문제가 될 수 있다. 이때 componentWillUnmount
로 비동기 요청을 정리하는 것이다.
componentWillUnmount() {
clearInterval(this.interval);
};
클래스의 경우 componentDidMount
나 componentDidUpdate
에서 모든 state를 조건문으로 분기 처리한다.
렌더 내부에서 onClick
과 같은 메서드에 함수 자체를 넣는 건 성능 최적화에 문제가 발생할 수 있으므로 따로 빼주는 것이 좋다. onClick
내부에서 바로 this
로 함수를 불러오게 하려면 () =>
를 해당 함수에 다시 넣어주어야 한다.
/* 수정 전 */
onClickBtn = (choice) => {
…
};
<button id="rock" className="btn" onClick={() => this.onClickBtn('바위')}>바위</button>
/* 수정 후 */
onClickBtn = (choice) => () => {
…
};
<button id="rock" className="btn" onClick={this.onClickBtn('바위')}>바위</button>
이와 같이 함수를 연달아 쓰는 패턴을 고차 함수라 한다.
✓주의: setState
를 연달아 사용하는 경우는 리액트가 알아서 한 번에 렌더링을 해준다.
훅스에는 componentDidMount
, componentDidUpdate
, componentWillUnmount
등과 같이 라이프사이클을 지원해주는 함수가 없다. 대신 사용하는 함수가 바로 useEffect
이다. useEffect
는 따로 함수처럼 만들어 사용한다.
useEffect(() => {
interval.current = setInterval(chagneHand, 100);
return () => {
clearInterval(interval.current);
}
}, [imgCoord]);
훅스의 useEffect
는 클래스의 라이프사이클 함수 세 개의 기능을 한 번에 담고 있기 때문에 아무래도 사용하기가 클래스보다 복잡한데, useEffect
의 함수 내부는 componentDidMount
와 componentDidUpdate
의 역할을 하고, return 내부는 componentWillUnmount
역할을 한다. useEffect
의 두번째 인수는 배열인데, 이 배열에 넣은 값들이 바뀔 때마다 useEffect
가 실행된다. 위의 코드에서는 imgCoord
가 바뀔 때마다 setInterval
이 실행되어야 하므로 배열 값에 imgCoord
가 들어간다.
배열 값에 여러 개의 state가 들어가도 되지만, 함수 내부에서 변화가 일어나는 state만 배열 값에 넣어주는 것이 좋다. useEffect
는 여러 번 사용이 가능하므로 여러 개의 state를 관리할 때에는 useEffect
를 따로 분리해주는 것이 좋다.
useEffect
의 특징은 렌더링이 될 때마다 실행과 종료를 반복한다는 것이다. 즉, 렌더링을 하면 setInterval
이 실행되고, 후에clearInterval
도 실행된다.
✓주의: useLayoutEffect
는 리사이징과 같은 화면의 레이아웃의 변화를 감지할 때 사용된다. 즉, 화면의 레이아웃이 바뀌기 전에 실행된다.
클래스의 라이프사이클은 해당 함수마다 모든 state들을 관리할 수 있는 반면에, 훅스의 useEffect
는 state 별로 함수를 실행한다고 생각하면 된다. 물론 인자의 배열 값에 여러 state를 넣어도 되지만, state의 값이 변할 때마다 useEffect
가 실행되므로 차라리 따로 분리해주는 편이 좋다.
인터페이스는 상호 간의 약속이라고 생각하면 쉽다. 변수나 함수를 정의할 때 인터페이스를 사용하면 해당 변수나 함수를 어떻게 사용해야하는지의 가이드가 되어준다. 라이브러리를 직접 만들거나 여러 명이서 동시에 협업을 할 때 미리 정의할 수 있으므로 자주 사용된다.
인터페이스를 활용하는 곳은 변수, 함수 뿐만이 아니라 함수 스택(구조), 인덱싱, 딕셔너리, 상속 등도 있다.
유료 강좌이기 때문에 코드는 생략!
타입 별칭은 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수를 의미한다. 어느 곳에서나 사용 가능하다.
/* string 타입을 사용할 때 */
const name: string = 'capt';
/* 타입 별칭을 사용할 때 */
type MyName = string;
const name: MyName = 'capt';
타입 별칭은 새로운 타입 값을 하나 생성하는 것이 아니라 정의한 타입에 대해 나중에 쉽게 참고할 수 있게 이름을 부여하는 것이다.
/* 인터페이스 */
interface Developer {
name: string;
skill: string;
}
let capt: Developer;
/* 타입 별칭 */
type Developer = {
name: string;
skill: string;
}
let thor: Developer;
VSCode에서 인터페이스와 타입의 프리뷰를 확인해 보면 차이점을 확인할 수 있다. 위의 코드에서 capt
변수의 타입을 정의했을 때의 프리뷰는 해당 인터페이스를 가리키고 있다. 반대로 thor
변수의 타입을 정의했을 때의 프리뷰는 해당 타입의 별칭을 모두 보여준다.
가장 큰 차이점은 인터페이스와 달리 타입은 확장이 불가능하다는 것이다. 그렇기 때문에 가능한 한 type
보다는 interface
로 선언해서 사용하는 것이 좋다.