My dimensions are not updating whenever the window is resized. In the code below you can see the window.innerHeight is updated, but the dimensions are not. I am probably missing something but I have not figured it out yet.
// Navbar.components.ts:
export const sidebar = () => {
let height;
let width;
if (typeof window !== `undefined`) {
height = window.innerHeight
width = window.innerWidth
}
const [dimensions, setDimensions] = useState({
windowHeight: height,
windowWidth: width,
})
useEffect(() => {
const debouncedHandleResize = debounce(function handleResize() {
setDimensions({
windowHeight: window.innerHeight,
windowWidth: window.innerWidth,
});
// Logging window.innerHeight gives the current height,
// Logging dimensions.windowHeight gives the initial height
console.log(window.innerHeight, " . ", dimensions.windowHeight)
}, 100);
window.addEventListener(`resize`, debouncedHandleResize)
return () => window.removeEventListener('resize', debouncedHandleResize)
}, [])
return {
open: () => ({
clipPath: `circle(${dimensions.windowHeight * 2 200}px at 40px 40px)`,
transition: {
type: "spring",
stiffness: 20,
restDelta: 2
}
}),
closed: () => ({
clipPath: `circle(30px at ${300 - 40}px ${dimensions.windowHeight - 45}px)`,
transition: {
delay: 0.2,
type: "spring",
stiffness: 400,
damping: 40
}
})
}
}
And I use the sidebar like this:
// Navbar.tsx
const Navbar: React.FC<NavbarProps> = () => {
...
return {
...
<MobileNavBackground variants={sidebar()} />
...
}
}
Here is an example of the logs that are returned when resizing the window:
Update 1
@sygmus1897
Code changed to this:
// Navbar.tsx:
const Navbar: React.FC<NavbarProps> = () => {
const [windowWidth, windowHeight] = getDimensions();
useEffect(() => {
}, [windowWidth, windowHeight])
return (
...
<MobileNavWrapper
initial={false}
animate={menuIsOpen ? "open" : "closed"}
custom={height}
ref={ref}
menuIsOpen={menuIsOpen}
>
<MobileNavBackground variants={sidebar} custom={windowHeight} />
<MobileNav menuIsOpen={menuIsOpen} toggleMenu={toggleMenu} />
<MenuToggle toggle={() => toggleMenu()} />
</MobileNavWrapper>
)
}
// getDimensions()
export const getDimensions = () => {
const [dimension, setDimension] = useState([window.innerWidth, window.innerHeight]);
useEffect(() => {
window.addEventListener("resize", () => {
setDimension([window.innerWidth, window.innerHeight])
});
return () => {
window.removeEventListener("resize", () => {
setDimension([window.innerWidth, window.innerHeight])
})
}
}, []);
return dimension;
};
// Navbar.components.ts
export const sidebar = {
open: (height) => ({
clipPath: `circle(${height 200}px at 40px 40px)`,
transition: {
type: "spring",
stiffness: 20,
restDelta: 2
}
}),
closed: (height) => ({
clipPath: `circle(30px at ${300 - 60}px ${height - 65}px)`,
transition: {
delay: 0.2,
type: "spring",
stiffness: 400,
damping: 40
}
})
}
The issue remains where resizing the window does not affect the clipPath position of the circle. To illustrate the issue visually, the hamburger is supposed to be inside the green circle:
CodePudding user response:
You can make a custom hook to listen to window resize.
You can modify solution from this link as per you requirement Custom hook for window resize
By using useState instead of ref, updating it on resize and returning the values to your main component
Here's an example:
export default function useWindowResize() {
const [dimension, setDimension] = useState([0, 0]);
useEffect(() => {
window.addEventListener("resize", () => {
setDimension([window.innerWidth, window.innerHeight])
});
return () => {
window.removeEventListener("resize", () => {
setDimension([window.innerWidth, window.innerHeight])
})
}
}, []);
return dimension;
}
and inside your main component use it like this:
const MainComponent = () => {
const [width, height] = useWindowResize();
useEffect(()=>{
// your operations
}, [width, height])
}
Your component will update every time the dimensions are changed. And you will get the updated width and height
EDIT:
Framer-motion provides a way to dynamically set variant's properties(for detailed guide refer to this Dynamically Update Variant) :-
// Navbar.tsx:
const Navbar: React.FC<NavbarProps> = () => {
return (
...
<MobileNavWrapper
initial={false}
custom={window.innerWidth} // custom={window.innerHeight} if variable depends on Height
animate={menuIsOpen ? "open" : "closed"}
custom={height}
ref={ref}
menuIsOpen={menuIsOpen}
>
<MobileNavBackground variants={sidebar} />
<MobileNav menuIsOpen={menuIsOpen} toggleMenu={toggleMenu} />
<MenuToggle toggle={() => toggleMenu()} />
</MobileNavWrapper>
)
}
// Navbar.components.ts
export const sidebar = {
open: (width) => ({
clipPath: `circle(${width 200}px at 40px 40px)`,
transition: {
type: "spring",
stiffness: 20,
restDelta: 2
}
}),
closed: (width) => ({
clipPath: `circle(30px at ${300 - 60}px ${width- 65}px)`,
transition: {
delay: 0.2,
type: "spring",
stiffness: 400,
damping: 40
}
})
}
CodePudding user response:
Thanks to this thread: Framer Motion - stale custom value - changing the custom value doesn't trigger an update I found that the issue I'm having is a bug in framer-motion. To resolve this issue, add a key value to the motion component that's having issues re-rendering. This makes sure React re-renders the component.
In my case all I had to do was this:
<MobileNavBackground variants={sidebar} custom={windowHeight} key={key} />