마지막 프로젝트 팀원들과 함께 프론트엔드 스터디를 시작했다!
프로젝트를 진행하면서 프론트엔드 기본지식이 조금 부족하다고 생각이 들었고 비슷한 생각을 한 팀원들과 함께 프론트엔드 스터디를 시작했다!
첫번째 주제는 React Life Cycle로 내가 제안한 주제였다. 이번 프로젝트를 진행하면서 class component를 function component로 리팩토링을 한 적이 있었는데 그 과정에서 react life cycle에 대해 좀 더 공부하고 싶다는 생각이 들었었다.
모든 리액트 컴포넌트는 생명주기가 존재한다.
컴포넌트는 생성(Mounting) -> 업데이트(Updating) -> 제거(Unmounting)의 생명주기를 가지며 클래스 컴포넌트는 라이프 사이클 메서드를 활용하고 함수 컴포넌트는 Hook을 사용한다.
React Life Cycle을 알아야 하는 이유!
💡 생명주기를 알고 생명주기에 따라 어떤 작업을 처리해줘야 하는지 지정해줘야 불필요한 리렌더링을 방지할 수 있다.
React Life Cycle methods diagram
컴포넌트의 인스턴스가 생성되어 DOM 상에 삽입될 때에 순서대로 호출된다.
constructor
static getDerivedStateFromProps()
render()
componentDidMount()
constructor
react 컴포넌트의 constructor는 해당 컴포넌트가 마운트되기 전에 호출된다.
constructor는 보통 아래 두 가지 목적을 위해 사용된다.
this.state
에 객체를 할당하여 지역 state를 초기화constructor(props) {
super(props);
// 여기서 this.setState()를 호출하면 안 됩니다!
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
getDerivedStateFromProps
getDerivedStateFromProps
는 props
로 받아온 것을 state
에 넣어주고 싶을 때 사용한다.
static getDerivedStateFromProps(nextProps, prevState) {
console.log("getDerivedStateFromProps");
if (nextProps.color !== prevState.color) {
return { color: nextProps.color };
}
return null;
}
다른 생명주기 메서드와는 달리 앞에 static
을 필요로 하고, 이 안에서는 this
를 조회 할 수 없다. 여기서 특정 객체를 반환하게 되면 해당 객체 안에 있는 내용들이 컴포넌트의 state
로 설정이 되고 반면 null
을 반환하게 되면 아무 일도 발생하지 않는다.
참고로 이 메서드는 컴포넌트가 처음 렌더링 되기 전에도 호출 되고, 그 이후 리렌더링 되기 전에도 매번 실행된다.
render()
UI를 렌더링 하는 메소드
→ 함수 컴포넌트로 치면 그 자체!
componentDidMount()
componentDidMount()
컴포넌트가 마운트된 직후 즉 트리에 삽입된 직후에 호출된다. DOM 노드가 있어야 하는 초기화 작업은 이 메서드에서 이루어지면 되며 라이브러리나 프레임워크의 함수를 호출하거나 이벤트 등록, setTimeout
, setInterval
과 같은 비동기 작업을 처리하면 되고, setState
호출도 이 메서드에서 호출하는 경우가 많다.
위와 같이 업데이트가 일어나는 상황에서 아래 메서드들이 순서대로 호출된다.
getDerivedStateFromProps
마운트 때 일어나는 메소드와 동일한 메소드이다!
shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)
컴포넌트가 리렌더링 할지 말지를 결정하는 메서드로 주로 최적화할 때 사용하는 메서드이며 useMemo와 비슷한 역할을 한다.
render()
getSnapshotBeforUpdate()
getSnapshotBeforeUpdate
는 컴포넌트에 변화가 일어나기 직전의 DOM 상태를 가져와서 특정 값을 반환하면 그 다음 발생하게 되는 componentDidUpdate
함수에서 받아와서 사용을 할 수 있다.
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate");
if (prevProps.color !== this.props.color) {
return this.myRef.style.color;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot)
컴포넌트 업데이트 작업이 끝난 직후 호출하는 메서드
리렌더링이 마치고 화면에 우리가 원하는 변화가 모두 반영되고 난 뒤 호출되는 메서드로 3번째 파라미터로 getSnapshotBeforUpdate
에서 반환한 값을 조회할 수 있다.
컴포넌트가 갱신되었을 때 DOM을 조작하기 위해서 이 메서드를 활용하면 좋으며 이전과 현재의 props를 비교하여 네트워크 요청을 보내는 작업도 이 메서드에서 이루어지면 된다.
컴포넌트를 제거하는 과정, 아래 메서드는 컴포넌트가 DOM 상에서 제거될 때 호출된다.
componentWillUnmount()
컴포넌트가 마운트 해제되어 제거되기 직전에 호출된다.
이 메서드 내에서 주로 DOM에 직접 등록했었던 이벤트를 제거하고, 만약에 setTimeout
을 걸은것이 있다면 clearTimeout
을 통하여 제거한다.
컴포넌트는 다시 렌더링되지 않으므로 componentWillUnmount()
내에서 setState()
를 호출하면 안된다.
컴포넌트 인스턴스가 마운트 해제되고 나면 절대로 다시 마운트되지 않는다.
→ 함수 컴포넌트에서 react state와 라이프 사이클 기능을 연동할 수 있게 해주는 함수이다. hook은 class 안에서는 동작하지 않으며 대신 class 없이 React를 사용할 수 있게 해주는 것이다.
→ class component의 단점들을 극복하기 위해 function component + hook이 도입된 것 같다.
리팩토링 할 때도 느꼈는데 처음에 function component + hook으로 배워서 그런지 나는 class component보다 function component + hook이 훨씬 사용하기에 편하다는 생각이 들었다.
useEffect(callBackFunc);
componentDidMount(), componentDidUpdate(), componentWillUnmount(), getDerivedStateFromProps()
의 역할을 모두 한다.useEffect(callBackFunc, []);
useEffect(callBackFunc, [state1, state2]);
외부 데이터에 구독(subscription)을 설정해야 하는 경우, 이런 경우에 메모리 누수가 발생하지 않도록 정리(clean-up)해야 한다.
useEffect(()=>{ return(() => func()) });