在我花时间进行反应和写几篇文章的过程中,我在问自己如何将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;
根据官方文档:
挂钩可以代替渲染道具和更高阶的组件吗?
通常,渲染道具和高阶组件仅渲染一个 儿童。我们认为,挂钩是服务此用例的更简单方法。那里 仍然是两种模式的地方(例如,虚拟滚动条 组件可能具有renderItem属性或可视容器 组件可能具有其自己的DOM结构)。但是在大多数情况下,Hooks 足够了,可以帮助减少树中的嵌套。
我使用此HOC只是为了向组件添加一些预定义的空间。
将其重构为钩子确实更好,请您解释一下为什么?
如果是,将其重构为钩子的最佳方法是什么?
答案 0 :(得分:1)
TDLR; 因为您的HOC没有任何状态或订阅,所以没有充分的理由使用钩子重构组件。
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组件。