使用 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 中的一个特殊props,将包含组件标签内的内容(这里<App name={name}/>是 inside Wrapper,所以它是children
请注意,您不一定需要使用children,它对于组件来说是唯一的,如果您愿意,您也可以使用普通props,或者混合props和子项:
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);
这对于许多用例来说既简单又好,我建议大多数消费者应用程序使用它。
渲染props
可以将渲染函数传递给组件,这种模式通常称为render prop,并且childrenprops通常用于提供该回调。
这种模式并不是真正用于布局。包装器组件通常用于保存和管理某些状态并将其注入其渲染函数中。
反例:
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>}
/>
截至今天,许多库都在使用渲染props(React context、React-motion、Apollo...),因为人们倾向于发现这个 API 比 HOC 更容易。react-powerplug是一个简单的 render-prop 组件的集合。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名称props不随时间变化,包装器可以说“我不需要渲染,因为props(实际上,名称)与以前相同”。使用children上面的基础解决方案,即使包装器是PureComponent,也不是这种情况,因为每次父渲染时都会重新创建子元素,这意味着即使包装的组件是纯的,包装器也可能总是重新渲染。有一个babel 插件可以帮助缓解这种情况并确保children元素随着时间的推移保持不变。
结论
高阶组件可以为您提供更好的性能。它并没有那么复杂,但一开始看起来肯定不友好。
阅读本文后,不要将整个代码库迁移到 HOC。请记住,在您的应用程序的关键路径上,出于性能原因,您可能希望使用 HOC 而不是运行时包装器,特别是如果多次使用相同的包装器,则值得考虑将其设为 HOC。
Redux 最初使用运行时包装器<Connect>,后来connect(options)(Comp)出于性能原因切换到 HOC (默认情况下,包装器是 pure 和 use 的shouldComponentUpdate)。这是我想在此答案中强调的内容的完美说明。
注意如果一个组件有render-prop API,通常很容易在它上面创建一个HOC,所以如果你是一个lib作者,你应该先写一个render prop API,最后提供一个HOC版本。这就是 Apollo 对<Query>render-prop 组件以及graphql使用它的HOC所做的。
就我个人而言,我两者都使用,但有疑问时我更喜欢 HOC,因为:
compose(hoc1,hoc2)(Comp)与渲染props相比,组合它们 ( )更惯用 
- 它可以给我更好的表现
 
- 我熟悉这种编程风格 
 
我会毫不犹豫地使用/创建我最喜欢的工具的 HOC 版本:
- React 的
Context.Consumer组合 
- 未说明的 
Subscribe 
- 使用
graphqlApollo 的 HOC 而不是Query渲染props 
在我看来,渲染props有时会使代码更具可读性,有时则更少......我尝试根据我的约束使用最实用的解决方案。有时可读性比性能更重要,有时则不然。明智地选择,不要拘泥于 2018 年将所有内容都转换为渲染props的趋势。