Reputation: 541
I have a state that tracks the window width:
const [innerWidth, setInnerWidth] = useState(window.innerWidth)
In useEffect
, I create a resize eventListener
which sets the state
to the new width:
useEffect(() => {
document.addEventListener('resize', () => {
setInnerWidth(window.innerWidth)
})
}, [])
Lastly, I have a function
test that logs the innerWidth
every 5 seconds, with an interval
started in useEffect
function test() {
console.log(innerWidth)
}
useEffect(() => {
setInterval(test, 5000)
}, [])
Unfortunately, despite any resize that happen, the test()
function
keeps on logging the original innerWidth
value.
How can I tell react to reload the test
function
as well?
EDIT:
The perpetual log of the innerWidth was just a simplification of my actual use case. Actually, the timer is shifting an element on the x-axis, and I need to know when it exceeds the width to stop the execution and start again.
Creating and invalidating a loop every time the window changes, like in several answers you've given, temporarily stops the shifting of my element, as the loop gets invalidated. I would like to avoid this.
Upvotes: 0
Views: 57
Reputation: 17
Edit: Your issue using the interval function is explained in this answer
This code works for me by logging the state variable using the effect hook:
const [innerWidth, setInnerWidth] = useState(window.innerWidth);
useEffect(() => {
const updateWidth = () => {
setInnerWidth(window.innerWidth);
};
window.addEventListener("resize", updateWidth);
}, []);
useEffect(() => {
console.log(innerWidth);
}, [innerWidth]);
I added the eventlistener using the window object.
Upvotes: 0
Reputation: 541
The solution was wrapping the innerWidth into an object, so that it is passed by reference and it 'updates' in the test
function
.
const innerWidthWrapper = {width: window.innerWidth}
useEffect(() => {
innerWidthWrapper.width = window.innerWidth
})
}, [])
Upvotes: 0
Reputation: 74
Can you change the test function to an anonymous function?
const test = () => {
console.log(innerWidth);
};
Change you useEffect:
useEffect(() => {
window.addEventListener('resize', () => {
setInnerWidth(window.innerWidth);
});
}, [setInnerWidth]);
Upvotes: 0
Reputation: 218847
The useEffect
created a closure around the original values, so that's all it ever logs. You'd need the effect to update any time the value changes, by adding it to the dependency array:
useEffect(() => {
setInterval(test, 5000)
}, [innerWidth])
This would of course create a new interval on every state change. So the useEffect
should return a function which cancels the interval:
useEffect(() => {
const x = setInterval(test, 5000);
return () => clearInterval(x);
}, [innerWidth])
That way there's only one interval running at any given time.
Though this begs the question... Why? If the goal is to log the value of innerWidth
to observe its changes, then why re-log the same value every 5 seconds indefinitely? Skip the test
function and the interval entirely and just log the value any time it changes:
useEffect(() => {
console.log(innerWidth);
}, [innerWidth])
Upvotes: 3