首页 > 解决方案 > 无法在 useEffect 中对未安装的组件执行 React 状态更新

问题描述

我有一个 REACT NATIVE 应用程序,在一个组件中,我用 AXIOS 调用一个 API 来从数据库中获取行。

我有loadData函数,它执行对数据库的调用并在状态中设置一些信息来监视执行并保存结果。我在useEffect中调用这个loadData但是当我改变屏幕时我收到Can't perform a React state update on an unmounted component

这是我的组件:

    const HomeScreen = props => {
    //I take the id from the state
    const Id = useSelector(state => state.auth.Id);



    const [data, setData] = useState();
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState();

    //Manage the duration of the http request
    const [executionDuration, setExecutionDuration] = useState(0);
    const [deleteExecutionCounting, setDeleteExecutionCounting] = useState(0);
    const executionDurationRef = useRef(executionDuration);
    executionDurationRef.current = executionDuration;
    const deleteExecutionCountingRef = useRef(deleteExecutionCounting);
    deleteExecutionCountingRef.current = deleteExecutionCounting;

    //call the api
    //the call to the api has made manually
    const loadData = useCallback(() => {

            setDeleteExecutionCounting(setInterval((() => {
                setExecutionDuration(executionDurationRef.current + 1);
            }), 2000));
            setError(false);
            setLoading(true);
            getRowsFromDb(Id).then(function (response) {
                if (response.status === 204) {
                    setData({ rows: [], count: 0 });
                }
                else {
                    setData(response.data);
                }
            })
            .catch(function (error) {
                setError(true)
            })
            .then(function () {
                // always executed
                clearInterval(deleteExecutionCountingRef.current);
                setExecutionDuration(0);
                setDeleteExecutionCounting(0);
                setLoading(false);
            });



    }, [Id]);

    //this is used to refresh the data every time the screen is visible
    useEffect(() => {
        const unsubscribe = props.navigation.addListener('focus', () => {
            // The screen is focused
            loadData();
        });

        // Return the function to unsubscribe from the event so it gets removed on unmount
        return unsubscribe;
    }, [Id, props.navigation, loadData]);

    useEffect(() => {
        loadData();


    }, [Id, props.navigation, loadData]);

    //check Loading state
    if (loading)
        return (
            <View style={styles.screenMessage}>
                <ActivityIndicator size='large' />
                {executionDurationRef.current > 3 &&
                    (
                        <Text>We're taking too long</Text>
                    )}
                {executionDurationRef.current > 6 &&
                    (<View>
                        <Text>there is something wrong</Text>
                    </View>
                    )}

            </View>
        )

    //check error state
    if (error) {
        console.log(errorOrders);
        return (
            <View style={styles.screenMessage}>
                <Error onPress={() => { loadData(); }}>Try again</Error>
            </View>
        )

    }

    //This is made for the first rendering to avoid to reach the code down when the value should be initialized
    if ((!loading && data === undefined)) {
        return null;
    }


    return (
       //normal rendering of a component
    );
};

const styles = StyleSheet.create({
    screenMessage: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: Colors.bodyBackgroundColor
    },
    bodyContainer: {
        flex: 1,
        justifyContent: "center",
        backgroundColor: Colors.bodyBackgroundColor
    },

});

export default HomeScreen;

我该如何解决这个问题?

标签: reactjsreact-nativeaxiosuse-effect

解决方案


推荐阅读