繁体   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