当发生反应阿波罗突变后,我的useEffect挂钩被触发时,如何从反应中解决此警告?

时间:2019-04-10 00:27:34

标签: reactjs graphql apollo react-apollo react-hooks

我的UI中有一个“卡片”列表,在任何给定时间只能扩展一张卡片。该列表具有一个react-apollo查询,该查询监视作业列表,并返回标记下一个未完成的作业(nextJobId)的属性。 useEffect挂钩跟踪此道具,nextJobId道具更新时,挂钩也会更新扩展卡。

每张卡的内部都有一个按钮,该按钮会触发react-apollo突变,从而更新数据库(将job.done设置为true),进而更新nextJobId道具。一旦发生这种情况,包含刚刚单击的按钮的卡片就会折叠,从而破坏按钮。

这似乎正在触发以下错误:

react-dom.development.js?61bb:507 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 the componentWillUnmount method.

我相信正在发生的事情是,在完成突变之前,正在更新apollo缓存(如果我向onCompleted组件添加了Mutation函数,它将永远不会被触发)。

这是钩子:

useEffect(() => {
  client.writeData({
    data: {
      openVisitId: nextJobId
    }
  })
}, [nextJobId])

这是突变:

mutation FinishJob($visitId: ID!) {
  updateJobInstance(data: { done: true }, where: { id: $visitId }) {
    done
    id
  }
}

到目前为止,我已经解决了两种方法:

1)将setTimeout添加到挂钩:

useEffect(() => {
  setTimeout(() => {
    client.writeData({
      data: {
        liveVisitId: nextJobId,
        openVisitId: nextJobId
      }
    })
  })
}, [nextJobId])

不知道为什么会这样。

2)从突变中删除done(我相信绕过了直接缓存更新),然后使用refetchQueries重新获取主列表:

mutation FinishJob($visitId: ID!) {
  updateJobInstance(data: { done: true }, where: { id: $visitId }) {
    id
  }
}
<Mutation mutation={FinishJob} refetchQueries={['CardList']}>...</Mutation>

这使我认为某种程度上缓存得到了乐观的更新,这导致在突变真正完成之前销毁了单击的按钮。是这样吗如果是这样,有什么办法告诉react-apollo在突变真正完成之前不要更新缓存?

1 个答案:

答案 0 :(得分:0)

此警告的意思是,您正在尝试更新已卸载组件的状态。 E.x您正在等待请求完成,然后将数据添加到状态中,但是该请求花费了很长时间,因此您正在导航到另一个页面。但是请求仍在完成,因此请求完成后无法将其数据添加到状态中。

因此,为了防止这种情况,最好使用_isMounted

function SomeName(){
    const _isMounted = false;

    useEffect(() => {
        _isMounted = true; //this is equivalent of componentDidMoun()
        return () => {
            _isMounted = false; //this is equivalent of componentWillUnmount()
        }
    }, [])
}

现在,每次需要更新状态时,都要检查其是否已挂载,以更新状态

if(_isMounted)
{
    this.setState({
        //your data
    })
}