Как очистить запрос Image.getSize при размонтировании компонента React Native?

У меня есть компонент React Native, который делает запрос Image.getSize для каждого изображения в компоненте. Затем в рамках обратного вызова запросов Image.getSize я устанавливаю некоторое состояние для своего компонента. Это все работает нормально, но проблема в том, что пользователь может перейти от экрана, на котором используется компонент, до того, Image.getSize ответит один или несколько запросов Image.getSize , что затем вызывает ошибку «утечка памяти без операции» вверх, потому что я пытаюсь изменить состояние после размонтирования компонента.

Итак, мой вопрос: как я могу остановить запрос Image.getSize от попытки изменить состояние после размонтирования компонента? Вот упрощенная версия моего кода компонента. Спасибо.

const imgWidth = 300; // Not actually static in the component, but doesn't matter.

const SomeComponent = (props) => {
    const [arr, setArr] = useState(props.someData);

    const setImgDimens = (arr) => {
        arr.forEach((arrItem, i) => {
            if (arrItem.imgPath) {
                const uri = `/path/to/${arrItem.imgPath}`;

                Image.getSize(uri, (width, height) => {
                    setArr((currArr) => {
                        const newWidth = imgWidth;
                        const ratio = newWidth / width;
                        const newHeight = ratio * height;

                        currArr = currArr.map((arrItem, idx) => {
                            if (idx === i) {
                                arrItem.width = newWidth;
                                arrItem.height = newHeight;
                            }

                            return arrItem;
                        });

                        return currArr;
                    });
                });
            }
        });
    };

    useEffect(() => {
        setImgDimens(arr);

        return () => {
            // Do I need to do something here?!
        };
    }, []);

    return (
        <FlatList
            data={arr}
            keyExtractor={(arrItem) => arrItem.id.toString()}
            renderItem={({ item }) => {
                return (
                    <View>
                        { item.imgPath ?
                            <Image
                                source={{ uri: `/path/to/${arrItem.imgPath}` }}
                            />
                            :
                            null
                        }
                    </View>
                );
            }}
        />
    );
};

export default SomeComponent;

Всего 1 ответ


Мне пришлось реализовать нечто подобное, я начинаю с инициализации переменной с именем isMounted .

Он устанавливает значение true когда компонент монтируется, и значение false когда компонент монтируется.

Перед вызовом setImgDimens необходимо проверить, смонтирован ли компонент. Если нет, он не будет вызывать функцию и, следовательно, не будет обновлять состояние.

const SomeComponent = (props) => {
  const isMounted = React.createRef(null);
  useEffect(() => {
    // Component has mounted
    isMounted.current = true;

    if(isMounted.current) {
      setImgDimens(arr);
    }

    return () => {
      // Component will unmount
      isMounted.current = false;
    }
  }, []);
}

Редактировать : это ответ, который работал для меня, но для того, чтобы он того стоил, мне пришлось переместить переменную isMounted за SomeComponent функции SomeComponent чтобы она работала. Кроме того, вы можете просто использовать обычную переменную вместо createRef для создания ссылки и т. Д.

В основном, у меня сработало следующее:

let isMounted;

const SomeComponent = (props) => {
    const setImgDimens = (arr) => {
        arr.forEach((arrItem, i) => {
            if (arrItem.imgPath) {
                const uri = `/path/to/${arrItem.imgPath}`;

                Image.getSize(uri, (width, height) => {
                    if (isMounted) { // Added this check.
                        setArr((currArr) => {
                            const newWidth = imgWidth;
                            const ratio = newWidth / width;
                            const newHeight = ratio * height;

                            currArr = currArr.map((arrItem, idx) => {
                                if (idx === i) {
                                    arrItem.width = newWidth;
                                    arrItem.height = newHeight;
                                }

                                return arrItem;
                            });

                            return currArr;
                        });
                    }
                });
            }
        });
    };

    useEffect(() => {
        isMounted = true;
        setImgDimens(arr);

        return () => {
            isMounted = false;
        }
    }, []);
};

Есть идеи?

10000