Function inside "setInterval" does not recieve updated variables from hooks
Asked Answered
M

1

2

In useEffect-hook I set interval, which is running function "calculateCircle". There I do some logic, including setting state(with useState-Hook). Variables from hooks are updated, I render and see them on page, but this function keeps consolloging old values.

I changed my component to the class-based component (without hooks) and everything is working now. But I wonder which is the problem using hooks.

const Features = () => {
 const block1 = React.createRef();
 const shadowText = React.createRef();

 const [ mouseIn, setMouseIn ] = useState(false);
 const [ xCircle, setXCircle] = useState(-50);

 const calculateCircle = () => {
    console.log('mouseIn :', mouseIn); //never changes, but in page - yes

    if (!mouseIn) {  //never skips this loop
        console.log('begin', xCircle);//always the same            
        let r = 50;
        let yCircle = Math.sqrt(r*r - xCircle*xCircle);
        if (shadowText.current) draw(xCircle, yCircle);
        setXCircle(prev => {
            console.log('xCircle:', prev);
            return prev > 50 ? -50 : prev + 1
        });            
        console.log('end', xCircle, yCircle);
    }            
} //on page I see that xCircle changes correctly

useEffect(() => {
    const cycle = setInterval(() => calculateCircle(), 1000);
    return () => {
        clearInterval(cycle);
    }
}, []);

//without hooks it works;

Moira answered 13/8, 2019 at 6:8 Comment(1)
Chech this question: #53024996Jumbo
M
2

Since calculateCircle instance is only refererrenced initially from within the useEffect hook, it takes the xCircle and mouseIn value from the closure at the time this function was created which for the setInterval is on initial call.

You need to pass the second argument to useEffect so that this method is created again on xCircle or mouseIn changes

const Features = () => {
 const block1 = React.createRef();
 const shadowText = React.createRef();

 const [ mouseIn, setMouseIn ] = useState(false);
 const [ xCircle, setXCircle] = useState(-50);

 const calculateCircle = () => {
    console.log('mouseIn :', mouseIn); //never changes, but in page - yes

    if (!mouseIn) {  //never skips this loop
        console.log('begin', xCircle);//always the same            
        let r = 50;
        let yCircle = Math.sqrt(r*r - xCircle*xCircle);
        if (shadowText.current) draw(xCircle, yCircle);
        setXCircle(prev => {
            console.log('xCircle:', prev);
            return prev > 50 ? -50 : prev + 1
        });            
        console.log('end', xCircle, yCircle);
    }            
} //on page I see that xCircle changes correctly

useEffect(() => {
    const cycle = setInterval(() => calculateCircle(), 1000);
    return () => {
        clearInterval(cycle);
    }
}, [mouseIn, xCircle]);
Merril answered 13/8, 2019 at 6:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.