为什么在此React Native组件中无法正确更新状态?

时间:2020-03-19 21:25:32

标签: javascript reactjs react-native settimeout use-effect

我有一个React Native组件正在多个屏幕上使用,在其中我使用重复出现的proc_open函数为图像轮播设置动画。轮播效果很好,但是我想在setTimeout钩子返回的回调函数中导航离开屏幕时正确清除计时器。 (如果我不清除计时器,则会收到一个令人讨厌的错误,并且我知道我仍然应该清除计时器。)

无论出于何种原因,我正在尝试将useEffect返回的回调中设置为setTimeout的状态变量设置为null

这是我的代码的简化版本:

useEffect

有人知道为什么状态无法正确更新以用于返回的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; 回调吗?谢谢。

3 个答案:

答案 0 :(得分:0)

您必须像这样从useEffect钩子中删除依赖项数组:

useEffect(() => {
    startCarouselCycle();

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

这是因为在安装组件时会触发一次效果,并且只会获得timeoutId的初始值。

答案 1 :(得分:0)

根据我所看到的,我认为没有必要将超时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;

答案 2 :(得分:0)

感谢大家的回答和反馈。我尝试执行每个人的建议,但无济于事。幸运的是,他们使我走上了正确的道路,据我所知,也许在我的组件中还有我没有提到的其他问题导致事情变得更加复杂。

同样,在将我的头撞在墙上几天之后,我可以通过以下方法解决此问题:

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;

我所做的主要更改是将timeoutId变量移至组件渲染功能的外部。渲染函数不断被调用,这导致timeoutId无法正确更新(不知道为什么;某些关闭问题?!)。

同样,将变量移至Carousel函数之外也可以解决问题。

相关问题