I have a component with a fixed positioned header and a body. body marginTop should be set dynamically based on the header clientHeight value. header Dom element is referenced with a useRef called headerRef, and body margin top is set with a useState hook. The margin setState function is called inside a useEffect which has one dependancy, headerRef.current?.clientHeight
. When header height changes and the page is re-rendered, I'm expecting a useEffect trigger and body marginTop reset, but the useEffect dependency is not working, hence the hook is not triggered.Any idea why this behaviour?
Here is a simple version of the code. the dynamic header content change is simulated with a setTimeout inside a useEffect hook.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>showcase</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="index.js" type="text/babel" ></script>
</body>
</html>
index.jsx
const e = React.createElement;
function StickyTop() {
const headerRef = React.useRef(null);
const [margin, setMargin] = React.useState("15px");
const [headerData, setHeaderData] = React.useState(
<div style={{ backgroundColor: "#e5e5e5" }}>header data loading...</div>
);
React.useEffect(() => {
setTimeout(
() =>
setHeaderData(
<div style={{ height: "100px", backgroundColor: "#e5e5e5" }}>
new header data
</div>
),
1000
);
}, []);
React.useEffect(() => {
if (headerRef.current.clientHeight) {
setMargin(headerRef.current.clientHeight);
}
}, [headerRef.current?.clientHeight]);
return (
<main>
<div ref={headerRef} style={{ position: "fixed", top: 0 }}>
{headerData}
</div>
<div style={{ marginTop: margin }}>the awsoem body</div>
</main>
);
}
const domContainer = document.querySelector("#root");
const root = ReactDOM.createRoot(domContainer);
root.render(e(StickyTop));