리액트 컴포넌트 패턴 HOC 를 합성함수로 예시

Felix Yi·2020년 3월 24일
0
post-custom-banner

next.js 에서 레이아웃이 hoc 소스 발견. 파다파다 보니까 결국 컴포넌트 패턴에 다다름. 함수 컴포지션까지 싹 공부함. 이해하니까 좋네. 근데 머리가 아파.

상태있는 vs 상태없는 컴포넌트

컴포넌트에 상태가 있을 수도 없을 수도 있다. 하지만 상태를 가지는 컴포넌트보다는 상태 없는 컴포넌트가 재사용성이 높다. 상태는 외부에서 제공하면 되거든.

바보 x 똑똑이 패턴

컨테이너 x 프레젠테이셔녈 패턴이라고도 불리운다.

바보는 아무것(상태)도 모른다. 오직 UI 만 안다.

const 사용자목록 = 외부상태매개변수 => 
	<ul>
    	{외부상태매개변수.사용자들.map( 한명 => (
        	<li>{한명.이름}- {한명.나이} 살이다</li>
        ))}
    </ul>

똑똑이는 (상태를)알고 기억하고 추적한다.

const 사용자목록_컨테이너 = () => {
	const fetch결과 = fetch사용자들();
    return ({
    	<사용자목록 사용자들={fetch결과}
    })
}

고차컴포넌트

추상화, 추상화를 통해서 어떤 컴포넌트를 받던 같은 결과 컴포넌트를 반환하는 함수를 고차 컴포넌트라고 한다.

구체적으로는 추후에 props를 받을 컨테이너 컴포넌트를 반환한다고 보면 될 거 같다.

export default ComposedComponent => {
     // 컨테이너 된, Wrrapped 된 컴포넌트 반환
    return props => <ComposedComponent {...props} />;
};

함수형 컴포넌트와 함수 합성비교

함수형을 이해하기 어려운 게 묶어서 사고하는 거. 수포자였던 나에게는 넘 어려운 이야기. 그래서 한번 파보고 옴: 커리와 함수합성 그리고 point-free 관점

함수 합성

 x. f. z = x(f(z(인자))

세 함수형 컴포넌트 합성해보자.

showProp

export default props => (
  <p>{props}<p>
);
const showProps = x => x +1

withLayout

export default ComposedComponent => {
  props => (
  <div>
    <ComposedComponent {...props} />
  </div>
);

// 헷갈리는 포인트. 커리된 함수라 인자를 추후에 받음

const withLayout = funcX => props =>  funcX(prop)*2

withData

export default ComposedComponent => {
    // withLayout 이 wrapped
    return props => <ComposedComponent {...props} />;
};

// 헷갈리는 포인트. 커리된 함수라 인자를 추후에 받음

const withLayout = funcY => props => funcY(prop)/4

오렇게 쓰는거고. 어쨌건 withData 가 props 를 받으니. withData 에서 주입된 prop 을 withLayout prop 에 넣고, 그렇게 주입된 prop 을 showProp 까지 주르륵 넣어주는 거.

const showProps = x => x +1
const withLayout = funcX => props => funcX(prop)*2
const withData = funcY => props => funcY(prop)/4

위 함수를 합성해보면 아래와 같이 나옴.

widhDate(withLayout(showProp)))

1. withLayout(showProp)
   withLayout(funcX) = props => funcX(prop)*2
2. widhData(withLayout(showProp))
   withLayout(funcY) = props => funcY(prop)/4
   = props => funcY(funcX(props+1)*2)/4)
   = funcY(funcX(props+1)*2)/4)(props)
   = ((props+1)*2)/4)(props)

즉, 처음 함수에 넣은 인자에 한가지 연산만 반복적으로 하는 것.

widhDate(withLayout(showProp)))(데이터)

기호만으로 이해하는 게 어렵다. 그럼 언어로 이해해보자.

인자를 받아서 합정 대상 함수에 전달,그래야 합성대상 함수 결과를 사용가능
const withData = funcY => x => funcY(x)/4
인자를 받아서 합정 대상 함수에 전달, 그래야 합성대상 함수 결과를 사용가능
const funcY = funcX => x => funcX(x)*2 // (funcX(x)*2)(x)
첫 합성 대상에서 인자를 전달 받아서 계산
const funcX = x => x +1
이제 계산이 시작됨.

funcY(자료) 
  = funcX(자료)*Y계산
   = (func(자료)*X계산)*Y계산
   = ((자료계산)X계산)Y계산)

// 
((props=> x+1)(props))*2
(((props=> x+1))*2)(props))/4
((((props=> x+1))*2))/4)(props)

대체 왜 인자를 대상함수에 넘겨주는 거야?
withData 는 인자를 받아서 showProps 에 넘겨줌.
왜냐면 showProps 계산이 되어야 연쇄적으로 계산을 할 거 아냐?


 withData(widhLayout(showProps))(인자)

결국 필요에 의한 거네. decomposition 을 해야 composition 할 수 있는데 decomposition 자체가 어렵고 생소하다.

요걸 redux compose 로도 표현할 수 있음

import { compose } from 'redux';

const 합성된컴포넌트 = compose(widhDate, widhLayout, showProp)

export default 합성된 컴포넌트

다른 컴포넌트에서 요거 사용.

return <합성된 컴포넌트 {...props} />
profile
다른 누구와도 같은 시장 육체 노동자
post-custom-banner

0개의 댓글