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

问题描述 投票:0回答:2

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

尽管出于某种原因,我试图将setTimeout返回的超时ID设置为从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;

没有人知道为什么状态无法正确更新以用于返回的useEffect回调吗?谢谢。

javascript reactjs react-native settimeout use-effect
2个回答
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的初始值。


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;
© www.soinside.com 2019 - 2024. All rights reserved.