繁体   English   中英

无法使用 useEffect() 和清理修复 React/NextJS memory 泄漏 function

[英]Unable to fix React/NextJS memory leak using useEffect() and cleanup function

我在页面上有一对功能组件挂钩, AddVocab组件将新词添加到数组, ListVocab映射该数组。

一切正常,直到我离开页面,然后出现此错误:

react_devtools_backend.js:3973 警告:无法对未安装的组件执行 React state 更新。 这是一个空操作,但它表明您的应用程序中存在 memory 泄漏。 要修复,请取消 useEffect 清理中的所有订阅和异步任务 function。

为了修复这个 memory 泄漏,我尝试了useEffect()的许多变体和清理 function 但无济于事。 我知道原因是卸载组件时异步VocabDataService Axios 调用未取消订阅/取消。

任何人都可以提供正确的useEffect()和清理 function 吗?

以下是相关文件:

组件/vocab/ListVocab.js

import React, { useState, useEffect } from "react";
import VocabDataService from "../../services/vocab";

export default function VocabList() {
    const [vocab, setVocab] = useState([]);
    const [currentVocab, setCurrentVocab] = useState(null);

    const retrieveVocab = () => {
        VocabDataService.getAll()
            .then((response) => {
                setVocab(response.data);
            })
            .catch((e) => {
                console.log(e);
            });
    };

    useEffect(() => retrieveVocab());

    const removeAllVocab = () => {
        VocabDataService.deleteAll()
            .then((response) => {
                setCurrentVocab(null);
            })
            .catch((e) => {
                console.log(e);
            });
    };

    return (
        <div>
            <div>
                <button onClick={removeAllVocab}>Delete</button>
                <ul>
                    {vocab.map((vocab, index) => (
                        <li key={index}>{vocab.word}</li>
                    ))}
                </ul>
            </div>
        </div>
    );
}

组件/vocab/AddVocab.js

import React, { useState } from "react";
import VocabDataService from "../../services/vocab";

export default function AddVocab() {
    const [id, setId] = useState(null);
    const [word, setWord] = useState("");
    const [translation, setTranslation] = useState("");
    const [starred, setStarred] = useState(false);
    const [submitted, setSubmitted] = useState(false);

    const onChangeWord = (e) => {
        setWord(e.target.value);
    };

    const onChangeTranslation = (e) => {
        setTranslation(e.target.value);
    };

    const saveVocab = () => {
        var data = {
            word: word,
            translation: translation,
        };

        VocabDataService.create(data)
            .then((response) => {
                setId(response.data.id);
                setWord(response.data.word);
                setTranslation(response.data.translation);
                setStarred(response.data.starred);
                setSubmitted(true);
            })
            .catch((e) => {
                console.log(e);
            });
    };

    const newVocab = () => {
        setId(null);
        setWord("");
        setTranslation("");
        setStarred(false);
        setSubmitted(false);
    };

    return (
        <div className="submit-form">
            {submitted ? (
                <>{newVocab()}</>
            ) : (
                <div>
                    <div className="form-group">
                        <label htmlFor="word">Word:</label>
                        <input
                            type="text"
                            className="form-control"
                            id="word"
                            required
                            value={word}
                            onChange={onChangeWord}
                            name="word"
                        />
                    </div>

                    <div className="form-group">
                        <label htmlFor="translation">Translation:</label>
                        <input
                            type="text"
                            className="form-control"
                            id="translation"
                            required
                            value={translation}
                            onChange={onChangeTranslation}
                            name="translation"
                        />
                    </div>

                    <button onClick={saveVocab} className="btn btn-success">
                        Submit
                    </button>
                </div>
            )}
        </div>
    );
}

页面/vocab.js

import React from "react";
import Routes from "../components/Routes";
import AddVocab from "../components/vocab/AddVocab";
import VocabList from "../components/vocab/VocabList";

export default function App() {
    return (
        <div>
            <Routes />
            <div>
                <AddVocab />
                <VocabList />
            </div>
        </div>
    );
}

谢谢!

useEffect 在其返回语句中有一个清理 function。

尝试这个:

useEffect(() => {
    let didCancel = false;
    if (!didCancel ) {
        retrieveVocab();
    }

    return() => {
        canceled = true;
    };
 });

或相同的方法,但就在更新 state 之前(效果中包含 function):

useEffect(() => {
    let didCancel = false;

    VocabDataService.getAll()
        .then((response) => {
            if (!didCancel) {
                setVocab(response.data);
            }
        })
        .catch((e) => {
            console.log(e);
        });

    return() => {
        didCancel = true;
    };
});

当需要“清理”时,React 将执行 function。 也就是说,当要卸载组件时。

注意:如果需要,可以使用 ref 而不是简单的变量。

看看React 文档

我希望这个对你有用

Memory 泄漏正在发生,因为您正在更新 state 而组件已卸载,因此在设置 state 时只需添加检查组件是否已安装。

if(mounted){
   setVocab(data);
}

如果已安装,此链接将帮助您检查/设置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM