重构到React钩子时的身份验证侦听器

时间:2019-04-05 12:08:38

标签: reactjs firebase-authentication react-hooks

从React类重构到React钩子时,我很难弄清楚如何更改身份验证处理组件。

这是我的中的相关代码:

  state = {
    user: null
  }

  componentDidMount() {

    authGetUser(user => {
      if (user !== this.state.user) {
        this.setState({user})
      }
    })
  }

  componentWillUnmount() {

    authUnsubscribe()
  }

  handleAuthClick = () => {

    if (this.state.user) {
      authSignOut()
    } else {
      authSignIn()
    }
  }

这里是钩子

  const [user, setUser] = useState<firebase.User | null>(null)

  useEffect(() => {
    return authUnsubscribe() // runs on mount and unmount only
  }, [])

  useEffect(() => {
    authGetUser(usr => setUser(usr))
  }, [])

  const handleAuthClick = () => {

    if (user) {
      authSignOut()
    } else {
      authSignIn()
    }
  }

另外,这是我其他相关方法:

const authGetUser = (callback: (user: firebase.User | null) => void) => {

  initFirebase()
  authUnsubscribe()
  userUnsubscribe = firebaseAuth.onAuthStateChanged(callback)
}

export const authUnsubscribe = () => {

  if (userUnsubscribe) {
    userUnsubscribe()
  }
}

const authSignIn = () => {

  googleAuth.signIn().then((googleUser: any) => {

    var credential = firebase.auth.GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token)

    firebaseAuth.signInAndRetrieveDataWithCredential(credential)
  })
}

const authSignOut = () => {

  googleAuth
  .signOut()
  .then(firebaseAuth.signOut())
}

两个示例均有效。但是,当我注销并使用hooks版本登录时,在控制台中收到一条错误消息,提示

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.

这表明清理未正确完成。

是的,我知道我可以继续使用适用于该类的版本。但是我想通过解决这个问题来更好地理解React挂钩。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

这对您不起作用吗?您可以使用一个useEffect()

React Hooks API DOCs

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      // Clean up the subscription
      setUser(null); // <--- TRY DOING SOMETHING LIKE THIS
      subscription.unsubscribe();
    };
  },
  [],
); 
  

清除功能在从UI删除组件之前运行   以防止内存泄漏。此外,如果一个组件呈现多个   次(通常如此),则在清除之前的效果之前   执行下一个效果。在我们的示例中,这意味着   每次更新都会创建订阅。为了避免对   每次更新,请参阅下一节。


  

如果您要运行效果并仅将其清理一次(在挂载和   卸载),则可以传递一个空数组([])作为第二个参数。这个   告诉React你的效果不依赖于道具的任何值   或状态,因此它不需要重新运行。这不是特殊处理   case —直接从依赖关系数组始终如何得出   有效。

答案 1 :(得分:0)

通常,当我们有异步请求并且之前未卸载组件并发生内存泄漏时,就会发生这种情况。显然,在基于类的组件中不会发生这种情况,因为我们有componentDidMount()componentWillUnmount()钩子,因此比useEffect()更自信我们已经操纵了状态,所以我认为您需要找出导致应用程序卸载的原因,并且有解决方案。

您应该使用一个useEffect()而不是这样的两个:

useEffect(() => {
  authGetUser(usr => setUser(usr))
  return authUnsubscribe() // runs on mount and unmount only
}, [])