Javascript 为什么此React本机组件中的状态未正确更新?

Javascript 为什么此React本机组件中的状态未正确更新?,javascript,reactjs,react-native,settimeout,use-effect,Javascript,Reactjs,React Native,Settimeout,Use Effect,我在多个屏幕上使用了一个React原生组件,其中我使用了一个重复出现的setTimeout函数来设置图像旋转的动画。旋转木马工作得很好,但我想在从useffecthook返回的回调函数中导航屏幕时正确清除计时器。(如果我没有清除计时器,那么我会出现严重错误,我知道我应该清理计时器。) 无论出于何种原因,我试图将setTimeout返回的超时ID设置为的状态变量似乎在从useffect返回的回调中设置为null 以下是我的代码的简化版本: const Carousel = () => {

我在多个屏幕上使用了一个React原生组件,其中我使用了一个重复出现的
setTimeout
函数来设置图像旋转的动画。旋转木马工作得很好,但我想在从
useffect
hook返回的回调函数中导航屏幕时正确清除计时器。(如果我没有清除计时器,那么我会出现严重错误,我知道我应该清理计时器。)

无论出于何种原因,我试图将
setTimeout
返回的超时ID设置为的状态变量似乎在从
useffect
返回的回调中设置为
null

以下是我的代码的简化版本:

const Carousel = () => {
    const [timeoutId, setTimeoutId] = useState(null);

    const startCarouselCycle = () => {
        const newTimeoutId = setTimeout(() => {
            // Code here that calls scrollToIndex for the FlatList.
        }, 5000);

        setTimeoutId(newTimeoutId);
    };

    const startNextCarouselCycle = () => {
        // Other code here.
        startCarouselCycle();
    };

    useEffect(() => {
        startCarouselCycle();

        return () => {
            // This is called when the screen with the carousel
            // is navigated away from, but timeoutId is null.
            // Why?!
            clearTimeout(timeoutId);
        };
    }, []);

    return (
        <FlatList
            // Non-essential code removed.
            horizontal={true}
            scrollEnabled={false}
            onMomentumScrollEnd={startNextCarouselCycle}
        />
    );
};

export default Carousel;
const Carousel=()=>{
const[timeoutId,setTimeoutId]=useState(null);
常量startCarouseCycle=()=>{
const newTimeoutId=setTimeout(()=>{
//这里的代码调用平面列表的scrollToIndex。
}, 5000);
setTimeoutId(newTimeoutId);
};
常量startNextCarouseCycle=()=>{
//这里还有其他代码。
StartCaruelCycle();
};
useffect(()=>{
StartCaruelCycle();
return()=>{
//当屏幕显示旋转木马时,将调用此选项
//已从中导航,但timeoutId为null。
//为什么?!
clearTimeout(timeoutId);
};
}, []);
返回(
);
};
导出默认旋转木马;

有人知道为什么状态不能正确更新以在返回的
useffect
回调中使用吗?谢谢。

您必须从
useffect
钩子中删除依赖项数组,如下所示:

useEffect(() => {
    startCarouselCycle();

    return () => {
        // This is called when the screen with the carousel
        // is navigated away from, but timeoutId is null.
        // Why?!
        clearTimeout(timeoutId);
    };
});

这是因为当组件挂载时,效果会触发一次,根据我所看到的情况,它只会获取
超时ID的初始值。我认为没有必要将超时ID存储在状态中。试试这个:

import React, { useState, useEffect } from 'react';
import { FlatList } from 'react-native';

const Carousel = () => {
    let _timeoutId = null

    const startCarouselCycle = () => {
        const newTimeoutId = setTimeout(() => {
            // Code here that calls scrollToIndex for the FlatList.
        }, 5000);

        _timeoutId = newTimeoutId;
    };

    const startNextCarouselCycle = () => {
        // Other code here.
        startCarouselCycle();
    };

    useEffect(() => {
        startCarouselCycle();

        return () => {
            // This is called when the screen with the carousel
            // is navigated away from, but timeoutId is null.
            // Why?!
            clearTimeout(_timeoutId);
        };
    }, []);

    return (
        <FlatList
            // Non-essential code removed.
            horizontal={true}
            scrollEnabled={false}
            onMomentumScrollEnd={startNextCarouselCycle} />
    );
};

export default Carousel;
import React,{useState,useffect}来自“React”;
从“react native”导入{FlatList};
康斯特旋转木马=()=>{
let _timeoutId=null
常量startCarouseCycle=()=>{
const newTimeoutId=setTimeout(()=>{
//这里的代码调用平面列表的scrollToIndex。
}, 5000);
_timeoutId=newTimeoutId;
};
常量startNextCarouseCycle=()=>{
//这里还有其他代码。
StartCaruelCycle();
};
useffect(()=>{
StartCaruelCycle();
return()=>{
//当屏幕显示旋转木马时,将调用此选项
//已从中导航,但timeoutId为null。
//为什么?!
clearTimeout(_timeoutId);
};
}, []);
返回(
);
};
导出默认旋转木马;

感谢大家的回答和反馈。我试着实现每个人的建议,但没有效果。幸运的是,他们让我走上了正确的道路,就我所知,也许我的组件中还有一些我在问题中没有提到的东西,导致事情变得更加复杂

尽管如此,在我的头撞在墙上几天后,我还是通过以下方法解决了这个问题:

let timeoutId;

const Carousel = () => {
    const startCarouselCycle = () => {
        timeoutId = setTimeout(() => {
            // Code here that calls scrollToIndex for the FlatList.
        }, 5000);
    };

    const startNextCarouselCycle = () => {
        // Other code here.
        startCarouselCycle();
    };

    useEffect(() => {
        startCarouselCycle();

        return () => {
            if (timeoutId) {
                clearTimeout(timeoutId);
            }
        };
    }, []);

    return (
        <FlatList
            // Non-essential code removed.
            horizontal={true}
            scrollEnabled={false}
            onMomentumScrollEnd={startNextCarouselCycle}
        />
    );
};

export default Carousel;
let timeoutId;
康斯特旋转木马=()=>{
常量startCarouseCycle=()=>{
timeoutId=setTimeout(()=>{
//这里的代码调用平面列表的scrollToIndex。
}, 5000);
};
常量startNextCarouseCycle=()=>{
//这里还有其他代码。
StartCaruelCycle();
};
useffect(()=>{
StartCaruelCycle();
return()=>{
if(超时ID){
clearTimeout(timeoutId);
}
};
}, []);
返回(
);
};
导出默认旋转木马;
我更改的主要内容是将
timeoutId
变量移动到组件渲染函数外部。渲染函数不断被调用,这导致
timeoutId
无法正确更新(不知道为什么;某些关闭问题?!)


尽管如此,将变量移到
Carousel
函数之外还是奏效了。

非常感谢,艾尔。这很有帮助。但是,如果我从
useffect
中删除
[]
参数,这不会导致组件不断刷新吗?此外,即使我保留了
[]
参数,我仍然不明白为什么会将状态锁定到第一个值。状态是在
useffect
函数之外设置的,因此我认为
useffect
只会在从
useffect
钩子返回回调时继承
timeoutId
的当前值。不是这样吗?非常混乱。无论如何,谢谢你。感谢您提供更多的见解。您将
timeoutId
存储在状态中有什么原因吗?试着像这样从函数中返回值,作为一个旋转木马,每次调用
setTimeout
函数时,它都会旋转一个图像,然后调用
startNextCarouselCycle
函数来启动一个新的
setTimeout
。因此,我需要始终知道最新的计时器ID是什么,然后在
useffect
中导航带组件的屏幕时使用该ID清除计时器。