簡體   English   中英

“無法在未安裝的組件上執行 React state 更新”錯誤

[英]The “Can't perform a React state update on an unmounted component” error

我有useEffect的問題,我從 firebase 加載數據,它可以工作.. 但有時控制台中的錯誤如下所示:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function, 
    in OrdersScreen (at SceneView.tsx:122)
    in StaticContainer
    in StaticContainer (at SceneView.tsx:115)
    in EnsureSingleNavigator (at SceneView.tsx:114)
    in SceneView (at useDescriptors.tsx:150)
    in RCTView (at CardContainer.tsx:221)
    in RCTView (at CardContainer.tsx:220)
    in RCTView (at CardSheet.tsx:33)
    in ForwardRef(CardSheet) (at Card.tsx:563)
    in RCTView (at createAnimatedComponent.js:144)
    in AnimatedComponent (at createAnimatedComponent.js:194)
    in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:545)
    in PanGestureHandler (at GestureHandlerNative.tsx:13)
    in PanGestureHandler (at Card.tsx:539)
    in RCTView (at createAnimatedComponent.js:144)
    in AnimatedComponent (at createAnimatedComponent.js:194)
    in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:535)
    in RCTView (at Card.tsx:529)
    in Card (at CardContainer.tsx:189)
    in CardContainer (at CardStack.tsx:558)
    in RCTView (at Screens.tsx:69)
    in MaybeScreen (at CardStack.tsx:551)
    in RCTView (at Screens.tsx:48)
    in MaybeScreenContainer (at CardStack.tsx:461)
    in CardStack (at StackView.tsx:458)
    in KeyboardManager (at StackView.tsx:456)
    in SafeAreaProviderCompat (at StackView.tsx:453)
    in RCTView (at StackView.tsx:452)
    in StackView (at createStackNavigator.tsx:85)
    in StackNavigator (at ShopNavigator.js:162)
    in OrdersNavigator (at SceneView.tsx:122)
    in StaticContainer
    in StaticContainer (at SceneView.tsx:115)
    in EnsureSingleNavigator (at SceneView.tsx:114)
    in SceneView (at useDescriptors.tsx:150)
    in RCTView (at ResourceSavingScene.tsx:43)
    in RCTView (at ResourceSavingScene.tsx:26)
    in ResourceSavingScene (at DrawerView.tsx:168)
* [native code]:null in __expoConsoleLog
- node_modules\react-native\Libraries\LogBox\LogBox.js:33:4 in console.error
- node_modules\react-native\Libraries\YellowBox\YellowBox.js:197:6 in registerError
- node_modules\react-native\Libraries\YellowBox\YellowBox.js:84:8 in errorImpl
- node_modules\react-native\Libraries\YellowBox\YellowBox.js:63:4 in console.error
- node_modules\expo\build\environment\muteWarnings.fx.js:27:4 in error
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:608:6 in warningWithoutStack
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:21972:25 in warnAboutUpdateOnUnmountedFiberInDEV
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:19813:40 in scheduleUpdateOnFiber
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:11880:16 in dispatchAction
* [native code]:null in dispatchAction
* screens\shop\OrdersScreen.js:28:15 in useCallback$argument_0
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:293:29 in invoke
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:154:27 in invoke
- node_modules\regenerator-runtime\runtime.js:164:18 in PromiseImpl.resolve.then$argument_0
- node_modules\promise\setimmediate\core.js:37:13 in tryCallOne
- node_modules\promise\setimmediate\core.js:123:24 in setImmediate$argument_0
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:135:14 in _callTimer
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:183:16 in _callImmediatesPass
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:446:30 in callImmediates
* [native code]:null in callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:396:6 in __callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:144:6 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:373:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:143:4 in flushedQueue
* [native code]:null in flushedQueue
* [native code]:null in invokeCallbackAndReturnFlushedQueue

還有我的OrdersScreen.js代碼:

import React, { useCallback, useEffect, useState } from 'react'
import { StyleSheet, View, Text, FlatList } from 'react-native'
import { useDispatch, useSelector } from 'react-redux'

import * as ordersActions from '../../store/actions/orders'
import OrderItem from '../../components/shop/OrderItem'
import Loading from '../../components/UI/Loading'
import ErrorMessage from '../../components/UI/ErrorMessage'

const OrdersScreen = (props) => {
    const [isLoading, setIsLoading] = useState(false)
    const [error, setError] = useState()
    const orders = useSelector((state) => state.orders.orders).sort(function (a, b) {
        return new Date(b.date) - new Date(a.date)
    })
    const dispatch = useDispatch()

    const loadOrders = useCallback(async () => {
        let mounted = true
        setError()
        setIsLoading(true)
        try {
            await dispatch(ordersActions.fetchOrders())
        } catch (err) {
            setError(err.message)
        }

        if (mounted) {
            setIsLoading(false)
        }

        return function cleanup() {
            mounted = false
        }
    }, [dispatch, setError, setIsLoading])

    useEffect(() => {
        loadOrders()
    }, [])

    if (error) {
        return <ErrorMessage onReload={loadOrders} />
    }

    if (isLoading) {
        return <Loading />
    }

    return (
        <View>
            <FlatList
                data={orders}
                keyExtractor={(item) => item.id}
                renderItem={(itemData) => (
                    <OrderItem
                        amount={itemData.item.totalAmount}
                        date={itemData.item.readableDate}
                        items={itemData.item.items}
                        status={itemData.item.status}
                    />
                )}
                ListEmptyComponent={
                    !isLoading && (
                        <Text style={{ textAlign: 'center', marginTop: 20 }}>
                            Ваш список заказов пока пуст.. 📄
                        </Text>
                    )
                }
            />
        </View>
    )
}

const styles = StyleSheet.create({
    screen: { flex: 1, justifyContent: 'center', alignItems: 'center' },
})

export default OrdersScreen

categories.js - 動作:

import Category from '../../models/categories'

export const SET_CATEGORIES = 'SET_CATEGORIES'

export const fetchCategories = () => {
    return async (dispatch, getState) => {
        try {
            const response = await fetch('https://shopapp-6f444.firebaseio.com/categories.json')

            if (!response.ok) {
                throw new Error('Something went wrong when we recieve categories')
            }

            const respData = await response.json()
            const loadedCategories = []

            for (const key in respData) {
                loadedCategories.push(
                    new Category(key, respData[key].title, respData[key].imageUrl, respData[key].description)
                )
            }

            dispatch({
                type: SET_CATEGORIES,
                categories: loadedCategories,
            })
        } catch (err) {
            throw err
        }
    }
}

請提供任何幫助或建議! 十分感謝!

您正在更改 catch 塊中的 react state,如果組件被卸載,在您的請求出錯期間,您很可能會看到該錯誤。

嘗試將 catch 塊的內容更改為:

 if (mounted) {
     setError(err.message)
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM