这三者是目前 react 解决代码复用的主要方式:
高阶组件(hoc)
官方解释: 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而 形成的设计模式。
简言之,HOC 是一种组件的设计模式,HOC 接受一个组件和额外的参 数(如果需要),返回一个新的组件。HOC 是纯函数,没有副作用。
// hoc的定义
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: selectData(DataSource, props)
};
}
// 一些通用的逻辑处理
render() {
// ... 并使用新数据渲染被包装的组件!
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
// 使用
const BlogPostWithSubscription = withSubscription(BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id));
HOC 的优缺点∶
优点∶ 逻辑服用、不影响被包裹组件的内部逻辑。
缺点∶ hoc 传递给被包裹组件的 props 容易和被包裹后的组件重名, 进而被覆盖
Render props
官方解释∶ "render prop"是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术。
具有 render prop 的组件接受一个返回 React 元素的函数,将 render 的渲染逻辑注入到组件内部。在这里,"render"的命名可以是任何其 他有效的标识符。
// DataProvider组件内部的渲染逻辑如下
class DataProvider extends React.Components {
state = {
name: 'Tom'
}
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token operator"><</span>div<span class="token operator">></span>
<span class="token operator"><</span>p<span class="token operator">></span>共享数据组件自己内部的渲染逻辑<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">)</span> <span class="token punctuation">}</span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
}
// 调用方式
<DataProvider render={data => (
<h1>Hello {data.name}</h1>
)}/>
优点:数据共享、代码复用,将组件内的 state 作为 props 传递给调 用者,将渲染逻辑交给调用者。
缺点:无法在 return 语句外访问数据、嵌套写法不够优雅。
Hooks
官方解释∶ Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情 况下使用 state 以及其他的 React 特性。通过自定义 hook,可以 复用代码逻辑。
// 自定义一个获取订阅数据的hook
function useSubscription() {
const data = DataSource.getComments();
return [data];
}
//
function CommentList(props) {
const {data} = props;
const [subData] = useSubscription();
...
}
// 使用
<CommentList data='hello' />
以上可以看出,hook 解决了 hoc 的 prop 覆盖的问题,同时使用的方 式解决了 render props 的嵌套地狱的问题。
hook 的优点如下∶ 使用直观; 解决 hoc 的 prop 重名问题; 解决 render props 因共享数据 而出现嵌套地狱的问题; 能在 return 之外使用数据的问题。
需要注意的是:hook 只能在组件顶层使用,不可在分支语句中使用。