Javascript 我得到错误:Can';即使我创建了清理,也不能对未安装的组件执行React状态更新

Javascript 我得到错误:Can';即使我创建了清理,也不能对未安装的组件执行React状态更新,javascript,node.js,reactjs,Javascript,Node.js,Reactjs,我的应用程序上的一个错误一直困扰着我 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. 我

我的应用程序上的一个错误一直困扰着我

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>
    );
};
我已经尝试了许多互联网提供的方法来解决这个问题,但不幸的是,它并没有解决我的问题

我在UsersTable.jsx和TeamTables.jsx中确实有useffect

这是我在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]);
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]);
这是我的TeamTable.jsx中的useEffect代码

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]);
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调用包装在makeCancelable方法中,并在组件卸载时取消它们

参考:

要做到这一点,请创建

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;
    },
  };
};
useffect

let fetchTeamsRequest = null;
并更新了
useffect
函数,如下所示

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]);

那么,您可以使用React建议的方法来解决此问题。您所需要做的就是将api调用包装在makeCancelable方法中,并在组件卸载时取消它们

参考:

要做到这一点,请创建

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;
    },
  };
};
useffect

let fetchTeamsRequest = null;
并更新了
useffect
函数,如下所示

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]);

那在我的Login.jsx中没有useEffect的呢?我应该实现相同的代码吗?您应该在发出异步请求的任何地方使用makeCancelable。不幸的是,这在我的Login.jsx文件上不起作用。您在Login.jsx上遇到了什么错误?与我遇到的错误相同;那在我的Login.jsx中没有useEffect的呢?我应该实现相同的代码吗?您应该在发出异步请求的任何地方使用makeCancelable。不幸的是,这在我的Login.jsx文件上不起作用。您在Login.jsx上遇到了什么错误?与我遇到的错误相同;