В React невозможность остановить запрос Ax ios при размонтировании компонента - PullRequest
0 голосов
/ 07 августа 2020

При выборке данных в React 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 a useEffect cleanup function. in ParentComponent является обычным предупреждением. Я прочитал несколько сообщений и предложений о том, как с этим справиться, и в настоящее время ни один из них не работает.

Для этого у нас есть функция useAxiosApi, которая извлекает данные асинхронно, и ParentComponent, который является компонентом, который использует useAxiosApi() и ему нужны данные. ParentComponent - компонент, который размонтируется / упоминается в предупреждениях.

Родительский компонент

import useAxiosApi...
function ParentComponent({ info }) {
    const dataConfig = { season: info.season, scope: info.scope };
    const [data, isLoading1, isError1] = useAxiosApi('this-endpoint', [], dataConfig);

    return (
        {isLoading && <p>We are loading...</p>}
        {!isLoading &&
            ... use the data to render something...
        }
    )
}

useAxiosApi

import axios from 'axios';
import { useState } from 'react';
import useDeepCompareEffect from 'use-deep-compare-effect';

const resources = {};
const useAxiosApi = (endpoint, initialValue, config) => {
    // Set Data-Fetching State
    const [data, setData] = useState(initialValue);
    const [isLoading, setIsLoading] = useState(true);
    const [isError, setIsError] = useState(false);

    // Use in lieu of useEffect
    useDeepCompareEffect(() => {
        // Token/Source should be created before "fetchData"
        let source = axios.CancelToken.source();
        let isMounted = true;

        // Create Function that makes Axios requests
        const fetchData = async () => {
            // For Live Search on keystroke, Save Fetches and Skip Fetch if Already Made
            if (endpoint === 'liveSearch' && resources[config.searchText]) {
                return [resources[config.searchText], false, false];
            }

            // Otherwise, Continue Forward
            setIsError(false);
            setIsLoading(true);
            try {
                const url = createUrl(endpoint, config);
                const result = await axios.get(url, { cancelToken: source.token });

                console.log('isMounted: ', isMounted);
                if (isMounted) {
                    setData(result.data);
                }

                // If LiveSearch, store the response to "resources"
                if (endpoint === 'liveSearch') {
                    resources[config.searchText] = result.data;
                }
            } catch (error) {
                setIsError(true);
            } finally {
                setIsLoading(false);
            }
        };

        // Call Function
        fetchData();

        // Cancel Request if needed in cleanup function
        return () => {
            console.log('Unmount or New Search? About to call source.cancel()');
            isMounted = false; // is this doing its job?
            source.cancel();
        };
    }, [endpoint, config]);

    // Return as length-3 array
    return [data, isLoading, isError];
};

export default useAxiosApi;

createUrl - это просто функция, которая принимает endpoint и dataConfig и создает URL-адрес, из которого будет извлекаться ax ios. Обратите внимание, что наши cancelTokens, похоже, работают вместе с поиском в реальном времени, так как новые поисковые запросы отменяют старые поисковые запросы, а сохранение результатов данных в resources для одной указанной c конечной точки liveSearch также работает.

Однако наша проблема в том, что при быстром отключении ParentComponent до завершения выборки данных мы все равно получаем предупреждение Cant perform a React state update. Я проверил console.logs(), и console.log('isMounted: ', isMounted) is всегда возвращает true , даже если мы быстро отключим компонент после его монтирования / до завершения выборки данных.

Мы ' Мы в недоумении по этому поводу, так как использование переменной isMounted - это способ, которым я видел решение этой проблемы раньше. Возможно, проблема связана с перехватом useDeepCompareEffect? Или, может быть, мы упускаем что-то еще. Мы будем очень благодарны за любую помощь или мысли по этому поводу.

Изменить: Мы также пытались создать переменную isMounted изнутри ParentComponent и передать ее в качестве параметра в useAxiosApi, но у нас это тоже не сработало ... В общем, было бы намного лучше, если бы мы могли обработать это предупреждение с помощью обновления нашей функции useAxiosApi, в отличие от ParentComponent.

Edit2: Похоже, что cancelToken работает только тогда, когда дублирующийся вызов API запускается для той же конечной точки. Это хорошо для нашего liveSearch, однако означает, что все другие выборки не отменяются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...