我想开发一个新功能,该功能以前会使用钩子包含在一个更高阶的组件中。但是,由于根据React Documentation:
“您不能在类组件内部使用Hooks,但是您绝对可以在单个树中将类和函数组件与Hooks混合使用。”
因此,假设我有一些现有的类组件ExistingComponent
,我想使用其他功能进行扩展,例如,监听window.resize
。我希望这样做。
// Existing Component
export class ExistingComponent extends React.Component {
render() {
return <div>I exist!</div>;
}
}
// Hook
export const useWindowResize = () => {
function resize() {
console.log('window resized!');
}
useEffect(() => {
window.addEventListener('resize', resize);
return function cleanup() {
window.removeEventListener('resize', resize);
};
});
};
// HOC
export const withWindowResize = component => {
useWindowResize();
return component;
};
// Extended Component
export const BetterComponent = withWindowResize(ExistingComponent);
但是,这在Uncaught Invariant Violation: Hooks can only be called inside the body of a function component.
上失败了,我确实使用了react-hot-loader
,但是我仍然能够在不返回类组件的组件函数中使用钩子。另外,我可以从函数中删除useWindowResize()
并按预期方式呈现。
我也能够呈现文档中提供的示例,因此我知道一般来说钩子不是问题:
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
这是错误的方法吗?
答案 0 :(得分:3)
您可以从withWindowResize
HOC返回一个新的函数组件,在其中调用该钩子并将props散布在传入的组件上。
您还可以将空数组作为第二个参数传递给useEffect
,以使其仅在初始渲染后运行一次。
const { useEffect } = React;
class ExistingComponent extends React.Component {
render() {
return <div>I exist!</div>;
}
}
const useWindowResize = () => {
useEffect(() => {
function resize() {
console.log('window resized!');
}
window.addEventListener('resize', resize);
return () => {
window.removeEventListener('resize', resize);
};
}, []);
};
const withWindowResize = Component => {
return (props) => {
useWindowResize();
return <Component {...props} />;
}
};
const BetterComponent = withWindowResize(ExistingComponent);
ReactDOM.render(<BetterComponent />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>