참고
- 아래 소스 코드를 순차 적으로 확인할 수 있다.
github 주소 - 아래 내용들을 다루고 있습니다.
## 4.3.1 고차 컴포넌트를 이용한 공통 기능 관리
* 코드 4-31 마운트 시 서버로 이벤트를 보내는 고차 컴포넌트
* 코드 4-32 마운트 여부를 알려주는 고차 컴포넌트
* 코드 4-33 로그인 여부에 따라 다르게 보여 주는 고차 컴포넌트
* 코드 4-34 클래스 상속을 이용한 고차 컴포넌트
* 코드 4-35 디버깅에 사용되는 고차 컴포넌트
* 코드 4-36 div요소로 감싸 주는 고차 컴포넌트
* 코드 4-37 여러 개의 고차 컴포넌트를 동시에 사용하기
* 코드 4-38 고차 컴포넌트에서 displayName 설정하기
* 코드 4-39 고차 컴포넌트에서 정적 메서드 전달하기
* 코드 4-40 withRouter 고차 컴포넌트
* 고차 컴포넌트 단점(04-40(withRouterExample).js 참고)
* withRouter, Router 예제코드`
## 4.3.2 렌더 속성값을 이용한 공통 기능 관리
* 코드 4-41 마운트 시 서버로 이벤트를 보내는 렌더 속성값
* 코드 4-42 children을 사용하지 않은 렌더 속성값
* 코드 4-43 데이터 처리 로직을 렌더 속성값으로 구현하기
* 코드 4-44 마우스의 위치 정보를 알려 주는 렌더 속성값
* 코드 4-45 렌더 속성값 함수의 매개변수를 속성값으로 전달하는 방법
* 코드 4-46 children 속성값을 이용해서 작성한 레이아웃 컴포넌트
고차 컴포넌트란?
- 컴포넌트를 입력으로 받아서 컴포넌트를 출력해주는 함수
- 입력 받은 함수에서 출력되는 컴포넌트 내부적으로 입력받은 컴포넌트를 사용하는데 이때 입력된 컴포넌트를 사용하는 방법은 무궁무진.
-
아래 두가지 방법으로 고차컴포넌트를 사용해서 공통기능 관리를 할 수 있다.
- 고차 컴포넌트를 이용한 공통 기능 관리
- 렌더 속성값을 이용한 공통 기능 관리
고차컴포넌틑 단점 세가지
첫번째 단점
- 속성값이 암묵적으로 넘어온다.
- react-redux의 connect고차 컴포넌트를 사용하면 사용자가 명시한 속성값 외에도 dispatch라는 함수가 암묵적으로 넘어온다.
따라서 connect 고차 컴포넌트를 사용한 컴포넌트 내부에서는 this.props.dispatch라는 코드가 등장한다.(모르는 사람은 의하게 생각할 수 있다)
두번째 단점
- 서로 다른 고차 컴포넌트가 똑같은 속성값 이름을 사용할 때 발생
- 만약 어떤 고차 컴포넌트가 dispatch라는 새로운 속성값을 만들어낸다고 가정할때 이 고차 컴포넌트와 react-redux의 connect 고차 컴포넌트를 동시에 사용하면 속성값 이름이 충돌하는 문제가 발생
- 마지막으로 호출된 고차 컴포넌트의 속성값으로 덮어써지게 된다.
- 우리가 만큼 고차 컴포넌트의 속성값을 수정하면 되지만 외부 패키지 속성값이 겹치면 같이 사용하기 힘들다.
세번째 단점
- 아래 세가지 의적인 절차가 필요
- 고차 컴포넌트를 만들 때는 항상 함수로 감싸줘야하고, displayName을 설정해 줘야하고, 정적 메서드를 전달하기 위한 코드가 필요하다(코드04-40 설명 참고)
- 특히 함수로 감싸져 있는 부분은 타입스크립트와 같은 정적 타입 언어를 사용할 때 타입을 정의하기 까다롭다는 문제가 있다.
렌더 속성값의 단점 세가지
첫번째 단점
- 렌더함수가 호출될 때마다 새로운 함수를 만들기 때문에 성능에 부정적인 영향을 준다.
- 하지만 최신 브라우저에서는 함수 생성이 성능에 거의 영향이 없을 정도로 많이 개선됐다.
- 오래된브라우저에서도 높은 성능이 요구되는 프로그램이 아니라면 크게 신경 쓰지 않아도 된다.
두번째 단점
-
다음과 같이 사용하는 쪽의 렌더함수가 복잡해질 수 있다.
- (1),(2),(3) 렌더 속성값이 중첩돼서 사용됐다.
function MyComponent() {
return (
<MountEvent name="MyComponent">
// (1)
{() => (
<DataFetcher // (2)
url="https://api.github.com/users/happyjy"
parseData={parseRepoData}
>
{({ data }) => (
<div>
<MouseTracer>
//(3)
{({ x, y }) => <p>{`(x,y): ${x}, ${y}`}</p>}
</MouseTracer>
<p>{`id: ${data.id}`}</p>
<p>{`html_url: ${data.html_url}`}</p>
<p>{`created_at: ${data.created_at}`}</p>
</div>
)}
</DataFetcher>
)}
</MountEvent>
);
}
고차컴포넌트 vs 렌더 속성값
- 렌더 속성값방법은 고차 컴포넌트가 갖고 있는 모든 단점이 존재 하지 않는다.
- 렌더 속성값에서 데이터는 함수의 매개변수로 명시적으로 넘어온다.
- 렌더 속성값은 함수의 매개변수를 통해서 개별적으로 필요한 정보를 주기 때문에
고차 컴포넌트가 갖고 있던 속성값 이름 충돌 문제도 존재하지 않는다. -
단, 생명주기 메서드에서 렌더 속성값의 데이터에 접근하기 위해서 Wrapper(코드4-45) 컴포넌트를 사용하는 경우에는 여전히 이름 충돌 문제가 존재한다.
- 그리고 고차 컴포넌트에서 필요했던 의례적인 절차가 필요없다.
- 일반적인 리액트 컴포넌트이기 때문에 타입스크립트와 같은 정적 타입 언어에서 타입으로 정의하는게 고차 컴포넌트 만큼 까다롭지도 않다.
-
고차 컴포넌트 함수의 호출은 입력되는 컴포넌트의 인스턴스가 만들어지기 전에 발생하기 때문에 정적이다.
- 반면 렌더 속성값은 렌더 함수를 호출 시에 동적으로 로직을 변경할 수 있다는 장점이 있다.
결론
- 고차 컴포넌트와, 렌더 속성값은 모두 코드 재사용성을 높이기 위한 리액트 코딩패턴이다.
- 거의 모든 겨웅에 있어서 고차 컴포넌트를 렌더 속성값으로 또는 그 반대로 변환할 수 있다.
- 어느쪽이 더 우월하다고 보기는 힘들며 각자의 취향과 프로젝트의 성격에 따라 어떤 패턴을 주로 사용할지 선택하면된다.