[ React ] 함수 컴포넌트, 선언문 vs 표현식은 취향 차이일까?

DD·2021년 5월 21일
37

React

목록 보기
3/4
post-thumbnail
post-custom-banner

왜 이런 글을 쓰게 되었나

이 글의 결론은 제 추측 임을 명심하세요!

  • 이 글은 하나의 궁금증에서 시작되었다.
  • 최근 react + typescript 를 공부하며 예전에 사둔 2019년 강의를 보았는데, 해당 강의에서 아래와 같이 CRA를 진행했다.

$ npx create-react-app . --typescript // 당시 typescript CRA. 현재는 아래와 같이 해야 한다.
$ npx create-react-app . --template typescript // 현재 typescript CRA

  • 여기서 눈에 띈 건 CRA의 결과로 생성된 템플릿에서 App.tsx가 아래와 같은 형태였다
const App: React.FC = () => {
	return ...
}
  • 함수 컴포넌트를 기본으로, 표현식으로 작성되어 React.FC를 타입으로 지정하고 있었다.
  • 하지만 강의를 보는 현재 (2021.5) CRA typescript를 해보면?
function App(){
	return ...
}
  • 띠용? 선언문으로 작성되어있다.
// 함수 선언문
function fn(){}
...
// 함수 표현식
const fn = () => {}

왜 선언문으로 바꿨을까.

  • 생각해보면 나는 이제까지 선언문으로 함수를 작성하다가 최근에야 표현식으로 함수를 작성하기 시작했다.
  • 사실 큰 이유는 없었다. 함수형 프로그래밍을 공부하면서 화살표 함수 사용 빈도가 늘었고, 화살표 함수가 더 최신이니까!! 같은 단순한 이유였을지도.. (물론 호이스팅이나 this 바인딩에 대한 이해는 하고 있다)

선언문 vs 표현식

이 글에서 알아볼 함수 선언문과 함수 표현식의 차이는 간단하게 다음과 같다.

  • 호이스팅 여부
  • export default를 선언과 동시에 할 수 있는가

이 두 가지 차이는 모두 '메인 로직과 그를 뒷받침하는 utils, helper를 구분하는' 과정에서 좀 더 깔끔한 코드를 지향할 때 문제가 될 수 있다.


호이스팅

  • 함수 선언문의 경우 함수 호이스팅이 가능해 선언부를 모두 모듈 하단에 내려놓고, 메인 로직만 상단에 배치함으로써 가독성을 높일 수 있다.

  • 표현식의 경우에도 실제 실행 로직은 없는 모듈의 경우에는 특별히 호이스팅 이슈에 걸리는 경우는 없다. 다만 TDZ(Temporal Dead Zone)은 표현식에서 항상 존재할 수 있는 이슈이다.

export default

// 선언문은 함수 선언과 export default를 동시에 할 수 있다.
export default Fn(){}

// 표현식은 불가능하다
export default const Fn = () => {} // error

// named export는 가능하다
export const Fn = () => {}
  • export default와 함수 선언을 동시에 한다는건 무슨 의미일까? default로 내보내는 함수는 그 모듈의 메인 로직 일테고, 이는 코드를 보는 사람으로 하여금 가장 중요한 로직이 무엇인지 인지시킬 수 있다. (그리고 편리하다)

  • 표현식을 지지하는 사람의 경우 "가장 중요한 메인 로직을 맨 위에 두면 똑같은거 아니냐"고 할 수도 있지만 먼저 언급한 호이스팅 이슈(TDZ)가 발생한다면 문제의 여지가 있다.

하지만 표현식도 장점이 있지

  • 클로저
  • 인자전달
  • IIFE(즉시 주입 함수 표현식)

이 내용은 검색해볼 것..!

React.FC or React.FunctionComponent

TypeScript로 React에서 함수 컴포넌트를 작성할 때, 표현식으로는 React.FC 타입을 지정했던 것 같다. 2019년도 근처 튜토리얼과 예제들은 대부분 React.FC를 사용했다. 다만 최근에는 React.FunctionComponent 타입을 지정하는 듯하다. 이 둘의 차이점은 찾아봐도 잘 나오지 않는다.. 같다는 사람도 있고.. 이 둘중 FunctionComponent가 더 낫다는 논란도 있었다고 한다! 자세한 정보를 찾을 수 없었다..

정정합니다. typescript 코드를 뜯어보니 FC와 FunctionComponent는 동일한 타입인 것 같습니다. 근데 왜 구분해놨는지는 모르겠음..

React.FC 특징

  • 함수 표현식 컴포넌트 함수의 타입으로 지정한다.
  • 함수 선언식에서는 사용할 수 없다. (엄밀히 말하면 지정할 수 있는 방법이 없다)
  • props의 타입을 Generics로 넣어서 사용한다. 이 경우 React.FC 타입의 컴포넌트 함수의 props에는 항상 children 속성이 존재한다
  • 이 자동 children은 장점 같지만, 타입을 명백히 해야하는 TypeScript의 취지에 어긋난다.
  • 그 외에 propTypes, defaultProps, displayName 등을 제공한다.
  • 하지만 defaultProps를 사용할 수 없다??
  • 이 문제를 해결하려면 defaultParameter를 이용해야한다. 혹은 React.FC를 사용하지 않으면 된다..

React.FC는 Generics를 사용할 수 없다?

  • 드롭다운, 리스트와 같은 라이브러리를 만든다고 가정해보자.
  • 해당 라이브러리는 어떤 타입의 아이템을 받을지 알 수 없는 재사용성 컴포넌트이다.
  • 이 경우에 TypeScript의 Generics가 필요한데, React.FC를 사용할 때 TypeScript는 Generics를 허용하지 않는다

이 문장은 오해의 소지가 좀 있고, 아직 좀 더 알아보는 중이다.
이 글과 번역본에서 No Generics 부분을 참조할 것!!

아마 표현식으로 이 글에서 이야기하는 "어떤 타입이든 받을 수 있는 재사용성 컴포넌트 라이브러리"를 만드는 방법이 반드시 있을 것 같은데, 아직까지는 찾지 못했다.
그렇지만 "라이브러리는 선언문으로만 만들어야한다"는 전제라니 믿을 수 없다..

다시, 왜 선언문으로 바꾸었을까? (추측!)

  • 메인/서브 로직을 구분하기 위해 호이스팅을 이용할 필요가 있다. (TDZ 방지)
  • export default와 선언을 동시에 함으로써 편리와 메인 로직을 명시함을 얻는다.
  • 함수 표현식으로 작성한 컴포넌트 함수(React.FC)의 한계
    • 지정하지 않은 속성값(children 등)이 props에 자동으로 추가됨
    • defaultProps를 사용할 수 없음
    • React.FC를 사용할 때 Generics를 사용할 수 없기 때문에 // 오해의 소지가 있음!!!

결론

바닐라만 쓸 때에는...

  • JavaScript를 공부하며 선언문, 표현식에 대해 공부했을 당시 내린 결론은 표현식이 더 낫다였다.

  • Airbnb 같은 큰 회사에서도 표현식을 코딩 스타일 가이드에서 권하고 있고,

  • 보통 호이스팅 같은 동작은 예상치 못한 결과를 일으킬 수 있으며,

  • 표현식을 통해서만 할 수 있는 각종 로직들이 존재 했기 때문이다.

    • 클로저
    • 먼저 함수를 선언해두고 if문에 따라 다른 함수 할당하기
    • 콜백함수에 바로 생성, 전달하기 등..

리액트에서는 ..?

  • 하지만 "리액트의 컴포넌트 함수" 에 한해서는 선언문이 더 나을지도.. 라는 생각이 들었다.

  • export default과 선언을 동시에, 호이스팅을 활용한 코드 정리로 보는 이로 하여금 한 눈에 메인 로직을 보여주게 하기를 우선시한다면, 바닐라에서 표현식을 쓸 때의 장점을 다소 희생?하더라도 더 나은 로직일까?하는 생각도 들었다

  • 게다가 모든 함수를 선언문으로 하겠다기보다 메인 로직에서만 그렇다는거니까??

  • 아니 그러면 표현식이랑 선언문이랑 섞어쓰게되는데.. 더 안 좋아보이기도..?

최종 결론

  • 뭔 소린지 모르겠다. 타입스크립트 더 공부하고 고쳐써야겠다..

참고

profile
기억보단 기록을 / TIL 전용 => https://velog.io/@jjuny546
post-custom-banner

3개의 댓글

comment-user-thumbnail
2022년 2월 13일

리액트 공부하는데 왜 const로 함수를 선언하는 지 궁금했는데 같은 고민을 하시는 분이 계셨군요ㅎㅎ 답은 없겠지만 정리를 좋아하는 저의 입장에서는 표현식 형태가 깔끔하게 정리되어서 좋지 않을까 하네요ㅎㅎ 좋은 포스팅 감사합니다!

답글 달기
comment-user-thumbnail
2022년 11월 12일

팀플 중인데 저희도 헷갈려서 그냥 표현식으로 통일하기로 했어요!

답글 달기
comment-user-thumbnail
2022년 11월 19일

검색하다보니 반가운 분이!! 똑같은 고민을 했다는게 재밌네요 ㅋㅋ 잘 봤습니당

답글 달기