簡體   English   中英

我得到錯誤:即使我創建了清理,也無法對未安裝的組件執行 React state 更新

[英]I get Error: Can't perform a React state update on an unmounted component even though i created cleanup

一個錯誤一直困擾着我的應用程序說

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.

我確實在我的上下文中聲明了一個 useEffect,以便我可以為我的應用程序存儲和獲取實時數據。

這是我在上下文中的代碼;

const FetchProvider = ({ children }) => {
    const [userList, setUserList] = useState([]);
    const [teamList, setTeamList] = useState([]);

    const authContext = useContext(AuthContext);
    const authAxios = axios.create({
        baseURL: process.env.REACT_APP_API_URL,
    });

    useEffect(() => {
        let isCancelled = false;
        if (
            authContext.isAuthenticated &&
            authContext.authState.userInfo !== null
        ) {
            const getUsers = async () => {
                try {
                    const users = await authAxios.get('/admin/get-all-users');
                    if (!isCancelled) {
                        setUserList(users.data);
                    }
                } catch (error) {
                    if (!isCancelled) {
                        console.log(error);
                    }
                }
            };

            const getTeams = async () => {
                try {
                    const teams = await authAxios.get('/get-all-teams');
                    if (!isCancelled) {
                        setTeamList(teams.data);
                    }
                } catch (error) {
                    if (!isCancelled) {
                        console.log(error);
                    }
                }
            };
            getUsers();
            getTeams();
        }
        return () => {
            isCancelled = true;
        };
    }, [authAxios, authContext]);

    return (
        <Provider
            value={{
                authAxios,
                userList,
                setUserList,
                teamList,
                setTeamList,
            }}
        >
            {children}
        </Provider>
    );
};

我在我的 Login.jsx 和我的 Login.jsx 中得到了這個錯誤,即使我在提交和聲明它時沒有聲明 useEffect 。

這是我的代碼;

const submitCredentials = async (credentials, resetForm) => {
        try {
            setLoginLoading(true);
            const { data } = await publicFetch.post('signin', credentials);
            authContext.setAuthState(data);
            setSignupSuccess(data.message);
            setSignupError('');
            setOpen(true);
            setTimeout(() => {
                setLoginLoading(false);
                setredirectOnlogin(true);
                resetForm(true);
            }, 400);
        } catch (error) {
            setLoginLoading(false);
            const { data } = error.response;
            setSignupError(data.message);
            setSignupSuccess('');
            setOpen(true);
        }
        return setLoginLoading(false);
    };

我已經嘗試了互聯網提供的許多方法來解決這個問題,但不幸的是它並沒有解決我的問題。

我的 UsersTable.jsx 和 TeamTables.jsx 中確實有 useEffect。

這是我在 UsersTable.jsx 中的代碼;

useEffect(() => {
        let isCancelled = false;
        const getUsers = async () => {
            try {
                const users = await fetchContext.authAxios.get('/admin/get-all-users');
                setIsLoaded(true);
                if (isLoaded === true) {
                    if (!isCancelled) {
                        fetchContext.setUserList(users.data);
                    }
                }
                return () => {
                    isCancelled = true;
                };
            } catch (error) {
                if (!isCancelled) {
                    console.log(error);
                }
            }
        };
        getUsers();
        return () => {
            isCancelled = true;
        };
    }, [fetchContext, isLoaded]);

這是我的 TeamTable.jsx 中的 useEffect 代碼;

useEffect(() => {
        let isCancelled = false;
        const getTeams = async () => {
            try {
                const teams = await fetchContext.authAxios.get('get-all-teams');
                setIsLoaded(true);
                if (isLoaded === true) {
                    if (!isCancelled) {
                        fetchContext.setTeamList(teams.data);
                    }
                }
            } catch (error) {
                if (!isCancelled) {
                    console.log(error);
                }
            }
        };
        getTeams();
        return () => {
            isCancelled = true;
        };
    }, [fetchContext, isLoaded]);

isLoaded 用作 AJAX

好吧,你可以使用 React 推薦的方法來解決這個問題。 您需要做的就是將 api 調用包裝在 makeCancellable 方法中,並在卸載組件時取消它們。

參考: https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

為此創建

const makeCancelable = (promise) => {
  let isCancelled = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      val => isCancelled ? reject({isCanceled: true}) : resolve(val),
      error => isCancelled ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      isCancelled = true;
    },
  };
};

為您的useEffect之外的請求創建一個變量

let fetchTeamsRequest = null;

並更新了您的useEffect function,如下所示。

useEffect(() => {
    const getTeams = async () => {
        if (fetchTeamsRequest) {
            try {
                await fetchTeamsRequest.promise;

                return;
            } catch (error) {
                return;
            }
        }

        fetchTeamsRequest = makeCancellable(fetchContext.authAxios.get('get-all-teams'));

        try {
            const teams = await fetchTeamsRequest.promise;

            fetchTeamsRequest = null;

            setIsLoaded(true);

            if (isLoaded === true) {
                if (!fetchTeamsRequest.isCancelled) {
                    fetchContext.setTeamList(teams.data);
                }
            }
        } catch (error) {
            if (!fetchTeamsRequest.isCancelled) {
                fetchTeamsRequest = null;
                console.log(error);
            }
        }
    };

    getTeams();

    return () => {
        if (fetchTeamsRequest) {
            fetchTeamsRequest.cancel();
        }
    };
}, [fetchContext, isLoaded]);

暫無
暫無

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

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