React useEffect 导致:无法对未安装的组件执行 React 状态更新

新手上路,请多包涵

获取数据时,我得到:无法对未安装的组件执行 React 状态更新。该应用程序仍然有效,但反应表明我可能会导致内存泄漏。

这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。”

为什么我不断收到此警告?

我尝试研究这些解决方案:

https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal

https://developer.mozilla.org/en-US/docs/Web/API/AbortController

但这仍然给了我警告。

const  ArtistProfile = props => {
  const [artistData, setArtistData] = useState(null)
  const token = props.spotifyAPI.user_token

  const fetchData = () => {
    const id = window.location.pathname.split("/").pop()
    console.log(id)
    props.spotifyAPI.getArtistProfile(id, ["album"], "US", 10)
    .then(data => {setArtistData(data)})
  }
  useEffect(() => {
    fetchData()
    return () => { props.spotifyAPI.cancelRequest() }
  }, [])

  return (
    <ArtistProfileContainer>
      <AlbumContainer>
        {artistData ? artistData.artistAlbums.items.map(album => {
          return (
            <AlbumTag
              image={album.images[0].url}
              name={album.name}
              artists={album.artists}
              key={album.id}
            />
          )
        })
        : null}
      </AlbumContainer>
    </ArtistProfileContainer>
  )
}

编辑:

在我的 api 文件中,我添加了一个 AbortController() 并使用了一个 signal ,以便我可以取消请求。

export function spotifyAPI() {
  const controller = new AbortController()
  const signal = controller.signal

// code ...

  this.getArtist = (id) => {
    return (
      fetch(
        `https://api.spotify.com/v1/artists/${id}`, {
        headers: {"Authorization": "Bearer " + this.user_token}
      }, {signal})
      .then(response => {
        return checkServerStat(response.status, response.json())
      })
    )
  }

  // code ...

  // this is my cancel method
  this.cancelRequest = () => controller.abort()
}

我的 spotify.getArtistProfile() 看起来像这样

this.getArtistProfile = (id,includeGroups,market,limit,offset) => {
  return Promise.all([
    this.getArtist(id),
    this.getArtistAlbums(id,includeGroups,market,limit,offset),
    this.getArtistTopTracks(id,market)
  ])
  .then(response => {
    return ({
      artist: response[0],
      artistAlbums: response[1],
      artistTopTracks: response[2]
    })
  })
}

但是因为我的信号用于在 Promise.all 中解决的单个 api 调用,所以我不能 abort() 承诺,所以我将始终设置状态。

原文由 Ryan Sam 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

fetch() 请求之间共享 AbortController 是正确的方法。

任何 Promise 中止时, Promise.all() 将拒绝 AbortError

 function Component(props) {
 const [fetched, setFetched] = React.useState(false);
 React.useEffect(() => {
 const ac = new AbortController();
 Promise.all([
 fetch('http://placekitten.com/1000/1000', {signal: ac.signal}),
 fetch('http://placekitten.com/2000/2000', {signal: ac.signal})
 ]).then(() => setFetched(true))
 .catch(ex => console.error(ex));
 return () => ac.abort(); // Abort both fetches on unmount
 }, []);
 return fetched;
 }
 const main = document.querySelector('main');
 ReactDOM.render(React.createElement(Component), main);
 setTimeout(() => ReactDOM.unmountComponentAtNode(main), 1); // Unmount after 1ms
 <script src="//cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.development.js"></script>
 <script src="//cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.development.js"></script>
 <main></main>

原文由 ⵗⵆⵗ 发布,翻译遵循 CC BY-SA 4.0 许可协议

对我来说,清除组件卸载中的状态很有帮助。

  const [state, setState] = useState({});

useEffect(() => {
    myFunction();
    return () => {
      setState({}); // This worked for me
    };
}, []);

const myFunction = () => {
    setState({
        name: 'Jhon',
        surname: 'Doe',
    })
}

原文由 Carlos Vallejo 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题