사용 children
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = ({name}) => (
<Wrapper>
<App name={name}/>
</Wrapper>
);
render(<WrappedApp name="toto"/>,node);
이것은 transclusion
Angular 라고도 합니다.
children
React의 특별한 소품이며 구성 요소의 태그 안에있는 것을 포함합니다 (여기 <App name={name}/>
에는 inside Wrapper
이므로children
children
구성 요소에 고유 한을 반드시 사용해야 할 필요는 없으며 원하는 경우 일반 소품도 사용하거나 소품과 자식을 혼합 할 수 있습니다.
const AppLayout = ({header,footer,children}) => (
<div className="app">
<div className="header">{header}</div>
<div className="body">{children}</div>
<div className="footer">{footer}</div>
</div>
);
const appElement = (
<AppLayout
header={<div>header</div>}
footer={<div>footer</div>}
>
<div>body</div>
</AppLayout>
);
render(appElement,node);
이것은 많은 유스 케이스에 간단하고 훌륭하며 대부분의 소비자 앱에 권장합니다.
소품을 렌더링
렌더링 함수를 구성 요소에 전달할 수 있으며이 패턴은 일반적으로이라고 render prop
하며 children
prop은 종종 해당 콜백을 제공하는 데 사용됩니다.
이 패턴은 실제로 레이아웃 용이 아닙니다. 랩퍼 구성 요소는 일반적으로 상태를 유지 및 관리하고 렌더링 기능에 삽입하는 데 사용됩니다.
카운터 예 :
const Counter = () => (
<State initial={0}>
{(val, set) => (
<div onClick={() => set(val + 1)}>
clicked {val} times
</div>
)}
</State>
);
훨씬 더 화려하고 객체를 제공 할 수 있습니다
<Promise promise={somePromise}>
{{
loading: () => <div>...</div>,
success: (data) => <div>{data.something}</div>,
error: (e) => <div>{e.message}</div>,
}}
</Promise>
반드시 사용할 필요는 없습니다 children
. 맛 / API 문제입니다.
<Promise
promise={somePromise}
renderLoading={() => <div>...</div>}
renderSuccess={(data) => <div>{data.something}</div>}
renderError={(e) => <div>{e.message}</div>}
/>
오늘날 많은 도서관은 사람들이이 API를 HOC보다 쉽게 찾는 경향이 있기 때문에 렌더링 소품 (React context, React-motion, Apollo ...)을 사용하고 있습니다. react-powerplug 는 간단한 렌더링 소품 구성 요소 모음입니다. react-adopt 는 작곡을 도와줍니다.
더 높은 주문 구성 요소 (HOC).
const wrapHOC = (WrappedComponent) => {
class Wrapper extends React.PureComponent {
render() {
return (
<div>
<div>header</div>
<div><WrappedComponent {...this.props}/></div>
<div>footer</div>
</div>
);
}
}
return Wrapper;
}
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = wrapHOC(App);
render(<WrappedApp name="toto"/>,node);
고차원 적 구성 요소 / HOC는 일반적으로 구성 요소를 소요하고 새 구성 요소를 반환하는 함수이다.
고차원 적 구성 요소를 사용하면 사용하는 것보다 더 확대됨에 될 수 children
또는 render props
래퍼는 단락 회로로 렌더링 한 단계 앞서 수있는 능력을 가질 수 있기 때문에, shouldComponentUpdate
.
여기서 우리는을 사용하고 PureComponent
있습니다. 앱을 다시 렌더링 할 때 WrappedApp
이름 소품이 시간이 지남에 따라 변경되지 않으면 래퍼는 "소품 (실제로 이름)이 이전과 같기 때문에 렌더링 할 필요가 없습니다"라고 말할 수 있습니다. 위의 children
기반 솔루션을 사용하면 래퍼가 PureComponent
인 경우에도 부모가 렌더링 할 때마다 자식 요소가 다시 만들어지기 때문에 그렇지 않습니다. 이는 래핑 된 구성 요소가 순수한 경우에도 래퍼가 항상 다시 렌더링 될 수 있음을 의미합니다. 이것을 완화 하고 시간이 지남에 따라 일정한 요소를 보장하는 데 도움 이되는 babel 플러그인 이 있습니다 children
.
결론
주문이 많을수록 성능이 향상됩니다. 그렇게 복잡하지는 않지만 처음에는 비우호적 인 것처럼 보입니다.
이 코드를 읽은 후 전체 코드베이스를 HOC로 마이그레이션하지 마십시오. 앱의 중요한 경로에서 성능상의 이유로 런타임 래퍼 대신 HOC를 사용할 수 있습니다. 특히 동일한 래퍼를 여러 번 사용하는 경우 HOC로 만드는 것이 좋습니다.
Redux는 처음에는 런타임 래퍼를 사용 <Connect>
하고 나중에 connect(options)(Comp)
성능상의 이유로 HOC로 전환했습니다 (기본적으로 래퍼는 순수하고 사용 shouldComponentUpdate
). 이것은이 답변에서 강조하고 싶었던 것을 완벽하게 보여줍니다.
컴포넌트에 render-prop API가있는 경우 일반적으로 그 위에 HOC를 작성하는 것이 쉽습니다. 따라서 lib 작성자 인 경우 먼저 render prop API를 작성하고 결국 HOC 버전을 제공해야합니다. 이것이 Apollo가 <Query>
render-prop 구성 요소와 graphql
HOC를 사용하여 수행하는 작업입니다.
개인적으로 두 가지를 모두 사용하지만 의심 스러울 때 HOC를 선호합니다.
compose(hoc1,hoc2)(Comp)
렌더링 소품과 비교하여 작곡하는 것이 관용적입니다 ( ).
- 그것은 더 나은 공연을 줄 수 있습니다
- 이 스타일의 프로그래밍에 익숙합니다
내가 좋아하는 도구의 HOC 버전을 사용 / 만들기를 주저하지 않습니다.
- 반응의
Context.Consumer
comp
- 미지의
Subscribe
- 렌더 소품
graphql
대신 아폴로 HOC 사용Query
내 의견으로는, 때로는 렌더링 소품이 코드를 더 읽기 쉽고 때로는 더 적게 만듭니다 ... 나는 내가 가진 제약 조건에 따라 가장 실용적인 솔루션을 사용하려고합니다. 때로는 가독성이 공연보다 중요하지만 때로는 그렇지 않습니다. 현명하게 선택하고 2018 년 모든 것을 렌더 소품으로 변환하는 추세를 따르지 마십시오.