我有以下内容:
// component.js
import React from 'react';
import useComponentSize from 'useComponentSize';
const component = () => {
const [comSize, comRef] = useComponentSize();
return (
<div style={{width: '100%'}} ref={comRef}>
<p>hi</p>
</div>
);
};
正在使用useComponentSize
,这是我制作的钩子:
// useComponentSize.js
import {
useRef,
useState,
useLayoutEffect,
} from 'react';
const useComponentSize = () => {
const [size, setSize] = useState({
width: 0,
height: 0,
});
const resizeRef = useRef();
useLayoutEffect(() => {
setSize(() => ({
width: resizeRef.current.clientWidth,
height: resizeRef.current.clientHeight,
}));
});
return [size, resizeRef];
};
export default useComponentSize;
但是由于某种原因我无法解决,它总是超过最大更新深度。我试过让useLayoutEffect
依赖于resizeRef
,我认为这会起作用,但是随后它不会再次更新(在反射时,正是我应该期望ref起作用的方式)。 / p>
我应该怎么做才能使其正常工作,最重要的是,为什么上述原因会导致无限循环?
编辑:使用事件侦听器的第二次尝试,仍然失败。我在这里想念什么概念?
// component.js
import React, { useRef } from 'react';
import useComponentSize from 'useComponentSize';
const component = () => {
const ref = useRef();
const [comSize] = useComponentSize(ref);
return (
<div style={{width: '100%'}} ref={ref}>
<p>hi</p>
</div>
);
};
import {
useRef,
useState,
useLayoutEffect,
} from 'react';
const useComponentSize = (ref) => {
const [size, setSize] = useState();
useLayoutEffect(() => {
const updateSize = () => {
setSize(ref.current.clientWidth);
}
ref.current.addEventListener('resize', updateSize);
updateSize();
return () => window.removeEventListener('resize', updateSize);
}, []);
return [size];
};
export default useComponentSize;
上面的编辑基于此useWindowSize
钩子,该钩子非常有用(我目前正在将其用作替代品,尽管我还是希望上面的方法能起作用,尤其是要知道为什么它不能起作用不起作用)。
对我要达到的目标的简短解释,因为之前没有明确指出:我希望状态size
在引用的组件的大小发生变化时进行更新。也就是说,如果窗口调整大小,并且组件保持相同的大小,则不应更新。但是,如果组件大小确实发生变化,则size
状态应更改值以反映这一点。
答案 0 :(得分:1)
由于您尚未将依赖项数组传递给useEffectLayout
钩子,因此您的代码陷入了无限循环。
实际上,您根本不需要使用useEffectLayout
钩子。您可以使用ResizeObserver API
来观察DOM元素的变化。
PS:尽管OP的问题已经通过在问题下方评论之一中发布的演示解决了,但我仍在为将来可能会看到此问题的任何人提供答案。< / p>
示例:
const useComponentSize = (comRef) => {
const [size, setSize] = React.useState({
width: 0,
height: 0
});
React.useEffect(() => {
const sizeObserver = new ResizeObserver((entries, observer) => {
entries.forEach(({ target }) => {
setSize({ width: target.clientWidth, height: target.clientHeight });
});
});
sizeObserver.observe(comRef.current);
return () => sizeObserver.disconnect();
}, [comRef]);
return [size];
};
function App() {
const comRef = React.useRef();
const [comSize] = useComponentSize(comRef);
return (
<div>
<textarea ref={comRef} placeholder="Change my size"></textarea>
<h1>{JSON.stringify(comSize)}</h1>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>