检查是否使用React钩子卸下了组件?

时间:2019-11-21 16:17:45

标签: reactjs react-hooks

我正在检查是否已卸载组件,以便不调用状态更新功能。

  1. 这是第一个选项,它有效
    const ref = useRef(false)
      useEffect(() => {
        ref.current = true
        return () => {
          ref.current = false
        }
      }, [])

    ....
    if (ref.current) {
      setAnswers(answers)
      setIsLoading(false)
    }
    ....
  1. 第二个选项正在使用useState,尽管我在组件安装后将其更改为isMounted,但true始终为false
  const [isMounted, setIsMounted] = useState(false)

  useEffect(() => {
    setIsMounted(true)
    return () => {
      setIsMounted(false)
    }
  }, [])

  ....
  if (isMounted) {
    setAnswers(answers)
    setIsLoading(false)
  }
  ....

与第一个选项相比,为什么第二个选项不起作用?

5 个答案:

答案 0 :(得分:0)

在没有较大上下文的情况下很难知道,但我认为您甚至不需要知道是否已装入某些内容。 useEffect(() => {...}, [])会在挂载时自动执行,您可以放任何所需的内容,直到挂载到该效果中为止。

答案 1 :(得分:0)

请仔细阅读此答案,直到最后。

似乎您的组件正在渲染多次,因此isMounted状态始终变为false,因为它不会在每次更新时都运行。它只运行一次就可以卸载。因此,您将在第二个选项数组中传递状态:

}, [isMounted])

现在,它将监视状态并在每次更新时运行效果。但是为什么第一种选择有效?

这是因为您使用的是useRef,它是异步的,而不是异步的useState。如果不清楚,请再次阅读有关useRef的文档:

  

之所以有效,是因为useRef()创建了一个纯JavaScript对象。 useRef()和自己创建{current:...}对象之间的唯一区别是useRef将在每个渲染器上为您提供相同的ref对象。


顺便说一句,您不需要清理任何东西。 DOM更改,第三方api反射等都需要清理过程。但是您不必养成清理状态的习惯。因此,您可以使用:

useEffect(() => {
    setIsMounted(true)
}, []) // you may watch isMounted state
     // if you're changing it's value from somewhere else

使用useRef钩子时,最好进行清理过程,因为它与dom变化有关。

答案 2 :(得分:0)

如果您要为此使用小型库,则react-tidy有一个自定义钩子,专门用于执行名为useIsMounted的钩子:

import React from 'react'
import {useIsMounted} from 'react-tidy'

function MyComponent() {
  const [data, setData] = React.useState(null)
  const isMounted = useIsMounted()
  React.useEffect(() => {
    fetchData().then((result) => {
      if (isMounted) {
        setData(result)
      }
    })
  }, [])
  // ...
}

Learn more about this hook

免责声明。我是该库的作者。

答案 3 :(得分:0)

我编写了这个自定义钩子,可以检查当前是否已安装组件,如果您需要长时间运行并且该组件可能在完成并更新UI状态之前已被卸载,则很有用。

import { useCallback, useEffect, useRef } from "react";

export function useIsMounted() {
  const isMountedRef = useRef(true);
  const isMounted = useCallback(() => isMountedRef.current, []);

  useEffect(() => {
    return () => void (isMountedRef.current = false);
  }, []);

  return isMounted;
}

用法

function MyComponent() {
  const [data, setData] = React.useState()
  const isMounted = useIsMounted()

  React.useEffect(() => {
    fetch().then((data) => {
      // at this point the component may already have been removed from the tree
      // so we need to check first before updating the component state
      if (isMounted()) {
        setData(data)
      }
    })
  }, [...])

  return (...)
}

实时演示

Edit 58979309/checking-if-a-component-is-unmounted-using-react-hooks

答案 4 :(得分:0)

这清除了我的错误消息,在我的 useEffect 中设置 return 取消订阅和异步任务。

  import React from 'react'

  const MyComponent = () => {
    
   const [fooState, setFooState] = React.useState(null)

   React.useEffect(()=> {

    //Mounted
     getFetch()
        

    // Unmounted
     return () => {
        setFooState(false)
     }
   })

      return (
        <div>Stuff</div>
      )
    }

export {MyComponent as default}