【问题标题】:Apollo client (react) - Cant update state on unmounted componentApollo 客户端(反应) - 无法更新未安装组件的状态
【发布时间】:2020-08-28 14:27:48
【问题描述】:

我试图在我的项目中实现社交身份验证并收到此错误:

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

有问题的组件从 facebook 接收代码,该代码被放入 url,用于重定向。

这是路线:

<PublicRoute exact path='/:callback?' component={Auth}/>

定义为:

export const PublicRoute = ({component: Component, ...rest}) => {
  const {client, loading, data} = useQuery(GET_USER, {fetchPolicy: 'cache-only'})
  let isAuthenticated = !!data.user.accessToken

  return (
    <Route {...rest} component={(props)=>(
      isAuthenticated ? (
        <Redirect to='/home' />
      ) : (
        <Component {...props} />
      )
    )}/>
  )  
}

我尝试在我的组件上使用钩子清理,但错误仍然存​​在。这是我当前的实现的样子:

const FaceookSignIn = () => {
  let _isMounted = false
  const client = useApolloClient()
  const appId = '187856148967924'
  const redirectUrl = `${document.location.protocol}//${document.location.host}/facebook-callback`;

  const code = (document.location.pathname === '/facebook-callback') ? querystring.parse(document.location.search)['?code'] : null
  const [loading, setLoading] = useState(false)
  const [callFacebook, data] = useMutation(FACEBOOK_SIGN_IN)

  useEffect(()=>{
    _isMounted = true
    if(!code) return
    if(_isMounted) callFacebook({variables: {code: code}})
    .then(res=>{
      const {error, name, email, accessToken} = res.data.facebookSignIn
      if (error) {
        alert(`Sign in error: ${error}`);
      } else {
        client.writeData({
          data: {
            user: {
              name: name,
              email: email,
              accessToken: accessToken,
              __typename: 'User'
            }
          }
        })
        setLoading(false)
      }
    })
    .catch(e=>{
      console.log(e)
      setLoading(false)
    })
    return ()=> _isMounted = false
  },[])

  const handleClick = e => {
    setLoading(true)
    e.preventDefault()
    window.location.href = `https://www.facebook.com/v2.9/dialog/oauth?client_id=${appId}&redirect_uri=${encodeURIComponent(redirectUrl)}`;
  }

  return (
    <a className="login-options__link" href='/facebook-login' onClick={handleClick}>
      {loading ? <p>loading...</p> : <img className="social-link__icon" src={fb.default} id="facebook" /> }
    </a>
  )
}

这种方法有些工作,加载凭据并将用户重定向到经过身份验证的路由,但控制台仍会抛出该错误,并且 ui 有时会在路由之间闪烁。我在这上面花了两天时间,我没有想法。我错过了什么明显的东西吗?

【问题讨论】:

  • _isMounted 在这里无效。它不会告诉您您的异步操作callFacebook 是否在 组件被卸载后解析。不要使用_isMounted,而是在您的清理处理程序中取消callFacebook 请求 - 这样您就不会在组件卸载后调用setLoading(false)
  • 感谢您的回复,但setLoading 不是这里的罪魁祸首,即使在完全删除它之后我收到同样的错误。我也在印象中阿波罗查询在卸载时会自动中止。无论如何我都会尝试取消它并返回

标签: reactjs redirect react-router apollo


【解决方案1】:

好吧,终于想通了,事实证明我不应该从 apollo 钩子中劫持逻辑并小心处理数据的方式。我假设突变挂钩会自行更新客户端状态,.then() 块在客户端更新和卸载组件之前解决。也许有人可以澄清一下?

如果有人感兴趣,这里是更新的代码:

const FaceookSignIn = (props) => {
  const appId = '187856148967924'
  const redirectUrl = `${document.location.protocol}//${document.location.host}/facebook-callback`
  const code = (document.location.pathname === '/facebook-callback') ? querystring.parse(document.location.search)['?code'] : null

//moved data handling logic to hooks optional callback
const [callFacebook, {client, data, loading, error, called}] = useMutation(FACEBOOK_SIGN_IN, {onCompleted: (data)=>{
    const {name, email, accessToken} = data.facebookSignIn
    client.writeData({
      data: {
        user: {
          name: name,
          email: email,
          accessToken: accessToken,
          __typename: 'User'
        }
      }
    })
  }})

  if(code && !called) {
    callFacebook({variables: {code: code}})
  }

  const handleClick = e => {
    e.preventDefault()
    window.location.href = `https://www.facebook.com/v2.9/dialog/oauth?client_id=${appId}&redirect_uri=${encodeURIComponent(redirectUrl)}`;
  }

  return (
    <a className="login-options__link" href='/facebook-login' onClick={handleClick}>
      {loading ? <p>loading...</p> : <img className="social-link__icon" src={fb.default} id="facebook" /> }
    </a>
  )
}

【讨论】:

    猜你喜欢
    • 2020-03-20
    • 1970-01-01
    • 2020-11-17
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 2019-10-19
    相关资源
    最近更新 更多