Santos의 개발블로그

React Render Props and HOC 이해하기 본문

Language & Framework & Library/React

React Render Props and HOC 이해하기

Santos 2023. 11. 26. 20:01

* 이 글은 Understanding React Render Props and HOC 번역하였습니다.

 

Understanding React Render Props and HOC

A detailed introduction to Render Props and Higher-Order Components in React

blog.bitsrc.io

React에서 Higher-Order-Components와 Render Props의 세부적으로 설명드립니다. 


요즘 React로 개발을 해보셨다면 HOC와 Render Props에 대한 개념을 한번쯤은 들어보셨을 것입니다. 이 글에서는 두가지 패턴에 대해서 이해해보고 왜 필요한지, 어떻게 올바르게 사용하여 좋은 application을 만들 수 있는지에 대하여 이야기해 보려고 합니다. 

Why do we need these patterns? 

React는 Component라는 것을 통해 코드 재사용에 대해 방법을 제공합니다. Component는 contents, style 그리고 business logic같은 많은 것들을 캡슐화합니다. 그래서 하나의 Component에서 우리는 하나의 목적을 가진 html, css 그리고 javaScript를 결합할 수 있습니다.  

 

Tip: Component를 위해 Bit(GitHub)를 사용해 보세요. app을 빠르게 build 할 수 있도록 조직, 공유, 재사용을 도와줄 것입니다. playground를 사용하거나 code를 install 함으로써 당신의 Component를 직접 찾아볼 수 있습니다.

 

teambit/bit

Build, distribute, and collaborate on components. Contribute to teambit/bit development by creating an account on GitHub.

github.com

Example

E-commerce application을 운영한다고 가정해봅시다. 이 서비스는 유저가 모든 상품들을 이용할 수 있는 지 볼 수 있고, 카트에 상품을 추가할 수 있습니다. 우리는 상품들의 데이터를 API를 통해서 보내고 상품 목록을 보여줍니다. 

 

이를 수행하는 React compnent는 다음과 같습니다. 

어드민쪽에서는 상품을 추가 또는 제거할 수 있는 관리 포털 페이지가 있습니다. 이 포털에서는 상품들의 데이터를 같은 API를 통해 가지고 오고, 상품 목록을 표 형식으로 보여줍니다.

 

이를 수행하는 React compnent는 다음과 같습니다. 

눈에 띄는 점은 두 Component 모두 상품의 데이터를 가져오는 로직이 구현되었다는 것입니다. 

 

앞으로는 다음과 같은 상황도 발생할 수 있다고 가정해봅시다.

 

1. 상품들의 데이터를 사용해야하고, 다른 방식으로도 보여주어야 합니다. 

2. 상품들의 데이터를 다른 API를 통해서 갖고와야 합니다. 그리고 상품리스트와 같은 방식으로 보여주어야 합니다.

3. API를 통해 데이터를 갖고오는 대신에 localStorage로부터 접근할 수 있어야 합니다. 

4. 표 형식의 상품 목록에서는 삭제 버튼 대신에 다른 기능이 가능한 버튼이 있어야 합니다.  

 

만약 다른 Component를 각각 만들어야 한다면, 많은 코드들을 복사해야 합니다. 

 

데이터를 가져오고 보여주는 것은 별개의 문제입니다. 미리 말하지만, 하나의 Component가 하나의 역할을 갖는 것이 더욱 좋습니다. 

 

한번 첫 번째 Component를 리팩토링을 해봅시다. 제품 데이터를 Props로 가져와 이전과 마찬가지로 제품 목록을 카드 형태로 rendering 합니다. component state와 라이프사이클 메서드가 필요하지 않기 때문에 함수 Component로 변환할 것입니다. 

 

코드는 아래와 같습니다. 

ProductList와 ProductTable은 prop으로써 상품의 데이터를 가지고 오는 함수 Component로 만들어 테이블의 row로 rendering 시킬 수 있습니다. 

 

이번에는 ProductsData 이름을 가진 Component를 만들어 보죠. 이는 상품들의 데이터를 API를 통해 가지고 옵니다. 데이터를 가져오고 state를 업데이트하는 것은 원래의 ProductList Component와 동일합니다. 그러면 이 Component의 render 메서드에는 어떤 코드를 써야 할까요? 

 

ProductList component를 단순하게 만든다면 ProductTable을 위해서 재사용할 수 없습니다. 하지만 이 Component가 rendering 할 항목을 요청할 수 있으면 문제가 해결됩니다. 한 곳에서 ProductList Component를 Rendering 하도록 만들고, 관리 포탈에서 ProductTable Component를 rendering 하도록 하면 됩니다. 

 

여기에서 render props와 HOC가 실행됩니다. 단지 Component가 무엇을 rendering 해야하는 지 묻은 방식일 뿐입니다. 이는 코드 재사용 이상의 효과를 가져옵니다. 

 

그것들이 왜 필요한지 알았으므로, 어떻게 사용을 할 수 있는지 알아봅시다. 

 

Render Props

Render Props를 개년 수준에서 이해하는 것은 매우 쉽습니다. React를 잠시 동안 잊고, JavaScript의 Context를 생각해보세요. 

 

2개의 숫자를 더하는 함수가 있습니다. 먼저 결과에 대한 로그를 찍어보죠. 코드는 아래와 같습니다. 

갑자기 sum 함수가 매우 유용하다는 것을 알게 되었고, 다른 곳에서도 필요하게 되었습니다. 그래서 콘솔에서 로그를 찍는 대신 sum 함수가 결과만을 제공할 수 있도록 바꾸었고, 호출자가 결과를 어떻게 사용할지를 결정하도록 하였습니다. 

 

아래와 같은 방식으로 말이죠 

sum 함수를 콜백 함수 인자로 보냈습니다. 다음 sum 함수는 결과를 계산하고 결과값을 인자로 fn을 호출했습니다. 

콜백 함수는 결과 값을 얻고, 그 결과로 무엇이든 할 수 있게 됩니다. 

 

이러한 방법은 render props의 핵심으로 만들어졌습니다. 이러한 패턴을 사용하여 더 명확한 부분을 얻을 것입니다. 그러면 한번 마주하고 있는 문제에 적용해 봅시다.

 

두개의 숫자를 더하는 함수 대신에 상품의 대한 데이터를 가지고 오는 ProductsData component가 있습니다. ProductsData component는 props를 통해 해당 함수를 가지고 옵니다. ProductsData component는 상품의 대한 데이터를 가져오고 데이터를 props로 가져온 함수에게 제공합니다. 그 함수는 상품의 데이터를 가지고 무엇이든 할 수 있게 됩니다.  코드는 아래와 같습니다. 

 

fn 인자처럼 함수가 전달되는 render prop이 있습니다. ProductData component는 상품에 대한 데이터를 인자로써 이 함수를 호출합니다. 

 

아래와 같은 방식으로 ProductData component를 사용할 수 있습니다. 

보시다시피 render props은 굉장히 다재다능한 패턴입니다. 대부분의 작업을 매우 간단하게 수행할 수 있습니다.  

 

중첩을 피하기 위한 단순한 방법은 component를 세분화된 component로 만들고 각각의 파일에서 사용하는 것입니다. 

또 다른 방법으로는  render props 안에서 길다란 함수를 만드는 것보다 많은 component 들을 만들고 구성하는 것입니다.

 

다음은 인기있는 패턴 HOC를 살펴보시죠.

Higher Order Components (HOC)

이 패턴에서 우리는 Component를 인자로 취한 함수를 정의하고 동일한 Component이면서 일부 기능이 추가된 Component를 반환합니다. 

 

이런 개념이 친숙하다면, Mobx에서 사용되는 데코레이터 패턴과 비슷하기 때문입니다. 대 다수의 언어는 데코레이터를 내부적으로 가지고 있고 JavaScript는 데코레이터를 곧 지원합니다. HOC는 데코레이터와 매우 비슷합니다.

 

HOC를 코드로 이해하는 것은 말로 하는 것보다 매우 쉽습니다. 그러면 코드를 함께 보시죠 

 보시다시피 데이터를 받아오고 state에 업데이트를 하는 것은 render props와 같습니다. 한가지 다른점이 있다면 Component 클래스가 함수 안에 정의되어 있는 것입니다. 함수는 인자로써 component를 취하고 우리가 전달해야 하는 Component에 prop를 더한 채로 render 메소드 내에서 반환합니다. 복잡한 이름을 가진 패턴이지만 구현은 꽤나 단순하죠? 

지금까지 우리는 왜 render props와 HOC 필요한지 어떻게 구현할 수 있는지 살펴보았습니다. 

 

그러나 아직 하나의 궁금증이 있습니다. render props와 HOC 중 어떻게 선택할 수 있을까요? 굉장히 다양하고 많은 자료들이 있게 지금 말씀드리지는 않겠습니다. 아마도 다음 포스트에서 가능할 것 같네요.

 

아래는 관련된 글들입니다. 

 

When to NOT use Render Props

Let's back up from the hype and think critically about the render props pattern

kentcdodds.com

 

 

Higher-order components vs Render Props

Decide when to use higher-order component over Render props.

www.richardkotze.com

Conclusion 

이번 시간에는 왜 이러한 패턴들이 필요하는지 각각의 패턴들의 핵심은 무엇이고 재사용 할수 있는 Component를 만들기 위해 어떻게 이러한 패턴들을 잘 사용해야 하는지에 대해서 살펴보았습니다. 

긴 글 읽어주셔서 감사합니다. 


< 참고자료 >

 

[사이트] #Midum

blog.bitsrc.io/understanding-react-render-props-and-hoc-b37a9576e196

 

Understanding React Render Props and HOC

A detailed introduction to Render Props and Higher-Order Components in React

blog.bitsrc.io

<React> Understanding React Render Props and HOC end

Comments