[REACT] 함수형 컴포넌트와 클래스형 컴포넌트의 차이를 아시나요?
예상 소요시간
10분
이 글을 다 읽고 나서는... 🤔
React에서의 함수형 / 클래스형 컴포넌트의 차이의 대해 확실히 알고,
목적에 따라 알맞은 컴포넌트 형식을 사용할 수 있는 능력을 갖추게 돼요!
목차
- 들어가기 앞서
- 클래스형 컴포넌트와 함수형 컴포넌트
- 컴포넌트?
- 클래스형 컴포넌트
- 함수형 컴포넌트의 반격 : Hook
- 클래스형 컴포넌트와 함수형 컴포넌트 간의 비교
- 결론
들어가기 앞서
💡 왜 React에서 컴포넌트를 생성하는 방법은 두 가지 일까?
안타깝게도 저는 위의 질문에 답을 하지 못했었습니다. (여러분은 어떠셨나요? 👀) React를 알고 본격적으로 사용한지 5개월이 넘었는데도, 한 번도 깊게 해 본 적 없던 고민이었죠. 클래스형 컴포넌트가 있다는 것은 알고 있었지만, 주위 아무도 클래스형 컴포넌트를 사용하지 않기에 저 또한 별생각 없이 함수형 컴포넌트만을 사용해 왔습니다.
그렇게 무지에 익숙해져 별 감흥 없이 살던 나날 중, 한 책 : '리액트를 다루는 기술'을 통해 클래스형 컴포넌트에 대해 다시한번 알게 되었습니다. 그리고 이 책은 클래스형 컴포넌트에 대해 알 필요가 있다고 말해주며, 해당 컴포넌트 형식의 중요성을 일깨워 주었습니다.
우리는 왜 클래스형 컴포넌트에 대해 알아야 할까요? 함수형 컴포넌트 만으로는 충분하지 않은걸까요? 왜 리액트 컴포넌트 생성 방식으로 클래스형, 함수형 두 가지가 있는 걸까요?
이 글은 위에 적힌 의문들에 대한 답을 알기 위해 공부한 것들을 정리 해 놓은 글입니다. 이 글을 읽은 여러분들도 혹시 과거의 저와 같은 의문이 있으시다면, 도움이 되시길 바랍니다.
클래스형 컴포넌트와 함수형 컴포넌트
컴포넌트?
컴포넌트란 독립적인 업무, 기능을 수행하는 부품(모듈)을 의미합니다.
사실 컴포넌트란 개념은 React이전에도 쭉 존재 해 왔습니다. 다만, 소프트웨어보다는 하드웨어에서 주로 다루어지는 개념이었죠. 기존의 소프트웨어는 컴포넌트 단위별로 쪼개어져 레고처럼 조립된 방식이 아닌, 소프트웨어 전체가 유기적으로 얽혀 한꺼번에 돌아가는 방식이었습니다. 이로 인해 특정 코드가 해당 소프트웨어에서 어떠한 역할을 하고 있는지 이해하기 어려웠고, 반복되는 코드도 많았으며, 유지보수가 어렵다는 단점으로까지 이어지게 되었죠. 개발자들은 코드를 나누고 정리할 필요성을 느끼게 되었고, 이로 인해 소프트웨어에 컴포넌트 개념을 도입하여 보다 효율적이고 잘 정리된 코드를 짤 수 있게 됩니다.
리액트 또한 렌더링을 효율적으로 하기 위해 DOM을 쪼개야 할 필요성을 느꼈습니다. 그리고 이같은 필요로 인해 리액트가 선택한 방식이 바로 컴포넌트였습니다. 리액트에서 컴포넌트는 '템플릿' 역할을 합니다. 주어진 데이터에 맞추어 UI를 생성할 뿐만 아니라, 라이프사이클 API를 통해 컴포넌트 생성, 소멸 등의 지점에서 특정 작업(메서드) 또한 실행 가능하죠. 이렇게 컴포넌트 단위로 작업을 하게 되면서 반복적인 작업이 크게 줄어들고 버그 수정과 협업이 쉬워지는 등 효율성이 증가하게 됩니다.
(이러한 효율성 증가는 리액트의 철학과도 일맥상통합니다.)
현재 리액트는 이러한 컴포넌트를 생성하기 위한 방식으로 클래스형 컴포넌트와 함수형 컴포넌트 두가지 모두를 지원합니다. 왜 컴포넌트 생성 방법에는 두 가지가 있는 걸까요?
클래스형 컴포넌트
두 방식 모두 처음부터 존재했지만, 둘 중 먼저 각광받은 방식은 클래스형 컴포넌트였습니다. 클래스형 컴포넌트는 ES6 당시 자바스크립트에 class가 추가되면서 사용할 수 있게 되었죠.
먼저 클래스형 컴포넌트의 구조에 대해 알아볼까요?
클래스형 컴포넌트는 크게 아래와 같은 구조로 이루어져 있습니다.
class MyComponent extends Component {
// state 부분
state = {
name : "클래스형 컴포넌트"
};
// 메서드 부분
handleName = () => {
this.setState({name : "새로운 이름"});
};
// render 부분
render(){
return <div>저는 클래스형 컴포넌트 입니다</div>
}
}
클래스형 컴포넌트는 class 키워드를 통해 선언하며 state, 메서드, render() 등으로 이루어져 있습니다. 이 중에서도 render()는 반드시 필요하며, 항상 JSX를 반환해야 한다는 특징이 있죠.
이러한 클래스의 가장 큰 장점은 무엇보다도 state와 라이프사이클* 기능을 사용할 수 있다는 것입니다. 당시의 함수형 컴포넌트는 state와 라이프사이클 기능을 사용하지 못하였기에, 컴포넌트의 기능을 온전히 다 할 수 없었죠. 또한 임의 메서드를 선언할 수 있는 등 함수형 컴포넌트에 비해 훨씬 많은 기능을 가진 클래스형 컴포넌트는 자연스럽게 함수형 컴포넌트를 제치고 리액트 개발자들에게 선호되었습니다.
LifeCycle API : 컴포넌트가 DOM 위에 생성되기 전 후 및 데이터가 변경되어 상태를 업데이트하기 전 후로 실행되는 메서드.
추후 다른 문서에서 자세히 다뤄 볼 예정
함수형 컴포넌트의 반격 : Hooks
리액트 버전 16.8에서 기념비적인 요소가 추가됩니다. 바로 'Hook' 이었죠. 그리고 이 요소는 리액트 컴포넌트의 흐름을 완전히 바꿔놓았습니다. Hook이 도입되면서, 함수형 컴포넌트에서도 state, 라이프사이클 관련 기능들을 사용할 수 있게 되었습니다.
기존의 함수형 컴포넌트의 구조를 볼까요?
function MyComponent() {
// state, 라이프 사이클 기능을 사용하기 어렵다.
return <div>나는 함수형 컴포넌트 입니다.</div>
}
위의 클래스형 컴포넌트에 비하면 정말 단순한 구조입니다. 함수형 컴포넌트의 가장 큰 장점이자, 단점이었죠. 그러나 이런 함수형 컴포넌트가 Hook을 만나게 되면서 아래와 같이 변하게 됩니다.
function MyComponent(){
const [name, setName] = useState("이름");
useEffect(() => console.log("hello from useEffect"), []);
return <div>저는 함수형 컴포넌트 {name} 입니다.</div>
}
useState와 useEffect가 추가된 게 보이시나요? useState, useEffect 등의 Hook을 통해 함수형 컴포넌트 또한 state를 자유롭게 사용할 수 있게 되었으며, 특정 라이프사이클 단계에서도 자유자재로 메서드를 실행할 수 있게 되었습니다. 함수형 프로그래밍의 단점이었던 state, 라이프사이클 API 사용 불가를 완벽하게 상쇄할 수 있게 되었죠. 그 외에도 간단한 구조, 더 적게 소요되는 메모리, 더 작은 빌드 후 용량 등의 장점으로 인해 함수형 컴포넌트는 클래스형 컴포넌트를 제치고 리액트 개발자들에게 각광받게 됩니다.
클래스형 컴포넌트와 함수형 컴포넌트 간의 비교
두 컴포넌트 형식의 차이는 표를 통해 보다 한눈에 비교할 수 있습니다.
state 기능 | 라이프 사이클 기능 | 메모리 자원 | 빌드 후 용량 | 구조 | |
클래스형 컴포넌트 | 사용 가능 | 사용 가능 | 많이 소요 | 많은 용량 | 복잡함 |
함수형 컴포넌트 | 사용 가능 (Hook을 통해) |
사용 가능 (Hook을 통해) |
적게 소요 | 적은 용량 | 간단함 |
cf. 빌드 후 용량은 차이가 있긴 하지만, 유의미하진 않을 정도이기에 크게 중요하게 여기지 않으셔도 됩니다.
이렇게 비교 해 보면 Hook이 도입된 이후로는 함수형 컴포넌트가 클래스형 컴포넌트에 비해 상위 호환인 것을 볼 수 있습니다. 효율을 중요하게 여기는 개발자 입장에서 왜 클래스가 아닌 함수형 컴포넌트를 사용하는지 어쩌면 그 이유를 알 것도 같습니다.
결론
우리는 위의 글을 통해 기존의 부족했던 함수형 컴포넌트가 Hook을 통해 클래스형 컴포넌트보다 여러 측면에서 상위 호환이 되었다는 것을 알 수 있었습니다. 그렇다면 둘 중 어느 컴포넌트 형식을 사용하는 것이 맞을까요?
개발에 정답은 없지만, 리액트 공식 매뉴얼에 따르면 컴포넌트를 새로 작성하게 된다면 함수형 컴포넌트를 사용하는 것을 권장한다고 합니다. 아무래도 여러 방면을 비교했을 때 함수형 컴포넌트가 클래스형 컴포넌트에 비해 더 효율적이라 판단하여 위와 같이 권장하는 것이겠지요.
관련 리액트 공식 문서 링크 : https://ko.reactjs.org/docs/hooks-intro.html
그렇다면, 함수형 컴포넌트 방식이 더 권장 되니 함수형 컴포넌트 방식에 대해서만 알면 될까요? 애석하게도 그건 아니라고 생각합니다. 지금은 함수형 컴포넌트가 더 각광받고 있으나, 과거 수년 동안 클래스형 컴포넌트 방식 또한 사용되어 왔습니다. 이러한 코드들은 레거시의 형태로 아직까지도 우리 일상에 남아있죠. 자신이 직접 작성하는 코드들 말고도, 이전의 레거시 코드들까지 다룰 줄 아는 프론트엔드 개발자가 되기 위해서는 반드시 클래스형 컴포넌트에 대해서도 알 필요가 있다고 생각합니다.
결론은, 함수형 컴포넌트를 주로 사용하되, 클래스형 컴포넌트에 대해서도 공부 해야 할 필요성이 있다는 것입니다.
역시 공부는 끝이 없는 것 같습니다 : )
마지막으로, 위의 글이 여러분의 의문을 해결하는데 조금이라도 도움이 되었기를 바라며 이만 글을 마치도록 하겠습니다.
끝까지 읽어주셔서 감사합니다 🙇🏻♀️
'FE' 카테고리의 다른 글
자바스크립트 배열 메서드 가이드 포스터 (번역) (0) | 2023.02.13 |
---|---|
[Next.js] 왜 새로워진 next/Image는 더이상 objectFit을 필요로 하지 않게 됐을까? (0) | 2022.12.17 |
[JS] LocalStorage & SessionStorage (0) | 2022.12.11 |
[Next.js] 프로젝트에 head 설정하기 (next/Head, _document.js, /app.head.js) (0) | 2022.12.08 |
[Next.js] 이미지 로딩 속도 개선하기 (0) | 2022.12.07 |