首页 > 解决方案 > reactjs组件错误与卸载

问题描述

从 reactjs 开始,我有一个我无法解决的问题。我尝试了很多来自互联网的示例,但我找不到编写此代码的正确方法。我为用户、公司和其他事物提供了更多这样的组件,但总的来说我得到了:

警告:无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。

  const mounted = useRef(true);

  useEffect(() => {
    socket.on('visiotrsnumber', (data) => {
       if (mounted.current === true) setVisitorsNumber(data)
    })
    socket.on('loggedlist', (data) => {
      if (mounted.current === true) setLoggedList(data)
    })
  }, []);

  const fetchUsers = async () => {
      try {
        const responseData = await sendRequest(
          'http://localhost:5000/api/users?page=1'
        );
        
        if (mounted.current === true){
          setLoadedUsers(responseData.pageOfItems);
          setTotalArticles(responseData.pager.totalItems);
          setPage(responseData.pager.currentPage);
        }   
      } catch (err) {}
  };

  const fetchUsersSearch = async () => {
    try {
      const responseData = await sendRequest(
        `http://localhost:5000/api/users/search?search=${encodeURI(searchTerm)}&page=1`
      );
      
      if (mounted.current === true){
        setLoadedUsers(responseData.pageOfItems);
        setTotalArticles(responseData.pager.totalItems);
        setPage(responseData.pager.currentPage);  
      }
    } catch (err) {}
  };

  useEffect(() => {
    !searchTerm ? fetchUsers() : fetchUsersSearch()     


    return () => {
      mounted.current=false;
    }    
  },[searchTerm, sendRequest]);

如果有人有一些例子,我应该如何正确地写这个?

标签: reactjs

解决方案


你有两个选择。要么使用一个组件范围的标志,要么为每个useEffect带有清理回调的钩子使用一个标志。这是两个选项的草图:

  • 组件宽标志
const mounted = useRef(false);
useEffect(() => {
  mounted.current = true;
  return () => mounted.current = false;
}, []);

// ...and usage example...
const fetchUsers = async () => {
  try {
    const responseData = await sendRequest('http://localhost:5000/api/users');
    if (mounted.current) {
      setLoadedUsers(responseData.pageOfItems);
    }
  } catch (error) {}
};
  • 每个useEffect带有清理回调的钩子一个标志
useEffect(() => {
  socket.on('visitorsnumber', setVisitorsNumber);
  socket.on('loggedlist', setLoggedList);
  return () => {
    socket.off('visitorsnumber', setVisitorsNumber);
    socket.off('loggedlist', setLoggedList);
  };
}, []);

const fetchUsers = async (token) => {
  try {
    const responseData = await sendRequest('http://localhost:5000/api/users');
    if (token.current) {
      setLoadedUsers(responseData.pageOfItems);
    }
  } catch (error) {}
};

useEffect(() => {
  const token = { current: true };
  if (searchTerm)
    fetchUsersSearch(token);
  else
    fetchUsers(token);
  return () => token.current = false;
}, [searchTerm, sendRequest]);

我个人认为第二种方法更清洁。它还有一个额外的好处是可以防止过时的响应覆盖更新的结果。


推荐阅读