[英]Refactor HOC as hook
在我花在 react 和几篇文章上的时间里,我问自己如何将 HOC 重构为钩子,以及它是否有用以及为什么,
这是一个重构的小组件
function withSpacing(Component) {
const WrappedWithSpacing = ({
pv, ph, pt, pb, pl, pr, style, ...props
}) => {
const styleWithSpacing = {};
const spacing = layout.padding;
const paddingTop = pt || pv;
const paddingBottom = pb || pv;
const paddingRight = pr || ph;
const paddingLeft = pl || ph;
if(paddingTop > 0) styleWithSpacing.paddingTop = paddingTop * spacing;
if(paddingBottom > 0) styleWithSpacing.paddingBottom = paddingBottom * spacing;
if(paddingLeft > 0) styleWithSpacing.paddingLeft = paddingLeft * spacing;
if(paddingRight > 0) styleWithSpacing.paddingRight = paddingRight * spacing;
return <Component style={{...style, ...styleWithSpacing}} {...props} />
}
WrappedWithSpacing.propTypes = {
pv: PropTypes.number,
ph: PropTypes.number,
pt: PropTypes.number,
pb: PropTypes.number,
pl: PropTypes.number,
pr: PropTypes.number,
style: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
}
WrappedWithSpacing.defaultProps = {
pv: 0,
ph: 0,
pt: 0,
pb: 0,
pr: 0,
pl: 0,
}
return WrappedWithSpacing;
}
export default withSpacing;
根据官方文档:
Hooks 会取代渲染道具和高阶组件吗?
通常,渲染道具和高阶组件仅渲染一个子组件。 我们认为 Hooks 是一种更简单的方法来服务于这个用例。 这两种模式仍有一席之地(例如,虚拟滚动组件可能有一个 renderItem 道具,或者可视化容器组件可能有自己的 DOM 结构)。 但在大多数情况下,Hooks 就足够了,可以帮助减少树中的嵌套。
我使用这个 HOC 只是为了向组件添加一些预定义的空间。
将它重构为钩子会更好,你能解释一下为什么吗?
如果是,那么将其重构为 hook 的最佳方法是什么?
TDLR; 因为您的 HOC 没有任何状态或订阅,所以没有正当理由使用钩子重构您的组件。
React Hooks 引入了几个新特性来作为 React Hooks 的补充,以补充其基于类的对应物。 useState
补充this.state
( docs ) 作为在渲染之间存储状态的功能方式。 useEffect
补充了componentDidMount
和componenetDidUnmount
方法 ( docs ),它提供了一种方法来执行功能性反应组件的设置和拆除。
如果您从文档中获取了这样的 HOC:
// This function takes a component...
function withSubscription(WrappedComponent, selectData) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
// ... that takes care of the subscription...
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// ... and renders the wrapped component with the fresh data!
// Notice that we pass through any additional props
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
并将其转换为功能组件,您可能会得到如下结果:
function withSubscription(WrappedComponent, selectData) {
return function WrappedComponent (props) {
const [myData, setMyData] = useState(null);
useEffect(() => {
const handleMyDataChange = newData => {
setMyData(newData);
}
DataSource.addChangeListener(handleMyDataChange);
return function cleanup() {
DataSource.removeChangeListener(handleMyDataChange);
};
});
return <WrappedComponent data={data} {...this.props} />;
}
您的填充和间距在每次渲染时都会重新生成。 由于您的问题中的代码在渲染之间没有任何持久性,因此尝试将其重构为实现 React Hooks 的组件没有多大意义。 React Hooks 更适合将基于类的 React 组件转换为功能性的 React 组件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.