如何在 React Hooks 中使用 componentWillMount()?

IT技术 javascript reactjs jsx react-hooks
2021-02-02 16:43:21

在 React 的官方文档中它提到 -

如果您熟悉 React 类的生命周期方法,您可以将 useEffect Hook 视为 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。

我的问题是 - 我们如何componentWillMount()在钩子中使用生命周期方法?

6个回答

你不能使用任何现有的生命周期方法(componentDidMountcomponentDidUpdatecomponentWillUnmount在钩等)。它们只能在类组件中使用。使用 Hooks,您只能在功能组件中使用。下面这行来自 React 文档:

如果你熟悉阵营类生命周期方法,你能想到的useEffect钩。因为componentDidMountcomponentDidUpdatecomponentWillUnmount结合。

建议是,您可以从功能组件中的类组件中模仿这些生命周期方法。

componentDidMount安装组件时,内部代码运行一次。useEffect这种行为的钩子等价物是

useEffect(() => {
  // Your code here
}, []);

注意这里的第二个参数(空数组)。这只会运行一次。

如果没有第二个参数useEffect钩子将在组件的每个渲染上被调用,这可能是危险的。

useEffect(() => {
  // Your code here
});

componentWillUnmount用于清理(如删除事件侦听器、取消计时器等)。假设您正在添加一个事件侦听器componentDidMount并将其删除,componentWillUnmount如下所示。

componentDidMount() {
  window.addEventListener('mousemove', () => {})
}

componentWillUnmount() {
  window.removeEventListener('mousemove', () => {})
}

相当于上面代码的钩子如下

useEffect(() => {
  window.addEventListener('mousemove', () => {});

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])
我现在真正理解了这个useEffect()功能,谢谢。
2021-03-18 16:43:21
@techexpert 该问题要求等效于componentWillMount,而不是componentWillUnmount这个答案确实根本没有回答这个问题,只是重申了 OP 已经暗示要知道的内容。
2021-03-23 16:43:21
对其他 Lifecycle 事件的很好解释,但这并不是专门针对 componentWillMount() 替代方案的问题。
2021-04-02 16:43:21
在 PanResponder 示例中,我看到 componentWillMount 似乎是必需的,否则您会得到未定义的 panHandler。
2021-04-06 16:43:21
为什么这是一个公认的答案?你没有提到一个钩子等价物componentWillMount
2021-04-12 16:43:21

useComponentWillMount 钩子

const useComponentWillMount = (cb) => {
    const willMount = useRef(true)

    if (willMount.current) cb()

    willMount.current = false
}

当出现序列问题(例如在另一个脚本之前运行)时,这个钩子可以是一个保护程序。如果不是这种情况,请使用更符合 React hooks 范式的 useComnponentDidMount。

useComponentDidMount 钩子

const useComponentDidMount = cb => useEffect(cb, []);

如果您知道您的效果应该在开始时只运行一次,请使用此解决方案。它只会在组件安装后运行一次。

使用效果范式

类组件具有生命周期方法,这些方法被定义为组件时间线中的点。钩子不遵循这种范式。相反,效果应该由它们的内容来构建。

function Post({postID}){
  const [post, setPost] = useState({})

  useEffect(()=>{
    fetchPosts(postID).then(
      (postObject) => setPost(postObject)
    )
  }, [postID])

  ...
}

在上面的示例中,效果处理获取帖子的内容。它具有依赖于 - 的值,而不是某个时间点postID每次postID获得新值(包括初始化)时,它都会重新运行。

组件将安装讨论

在类组件中 componentWillMount 被认为是遗留的(源 1源 2)。它是遗留的,因为它可能运行不止一次,还有一种替代方法 - 使用构造函数。这些注意事项与功能组件无关。

唯一的问题是由于涉及状态更新,您会获得额外的渲染。通过使用 ref,您无需额外渲染即可获得所需的行为:` const useComponentWillMount = func => { const willMount = useRef(true); useEffect(() => { willMount.current = false; }, []); if (willMount.current) { func(); } }; `
2021-03-21 16:43:21
@PaoloMoretti,谢谢。这个 componentWillMount 钩子不是类组件中 componentWillMount 生命周期的完全等价物。但是,传递给它的函数将立即运行,仅在第一次调用时才运行。这实际上意味着它将在呈现之前运行,甚至在它第一次返回值之前运行。我们能同意吗?我同意使用名称 componentWillMount 并不理想,因为这个名称在类生命周期版本中具有一定的含义。也许我最好称它为“useRunPreMount”。
2021-03-26 16:43:21
这是唯一能回答问题且有意义的答案。谢谢!
2021-03-31 16:43:21
这种componentWillMount基于的功能实现 useEffect有两个问题。第一个是功能组件中没有安装生命周期,两个钩子都将在组件呈现后运行,因此Runs only once before component mounts具有误导性。第二个是componentWillMount在服务器渲染时调用,而useEffect不是。许多库仍然依赖,UNSAFE_componentWillMount因为目前它是触发副作用服务器端的唯一方法。
2021-03-31 16:43:21
@PaoloMoretti,我不太明白。我不使用 SSR,但我的理解是在 SSR 上 componentWillMount 运行两次 - 一次在服务器上,一次在客户端上。我认为传递给 useComponentDidMount 的回调也是如此。useComponentDidMount 中继 useEffect 以停止调用回调。在 useEffect 的回调执行之前,组件的函数将运行两次 - 一次在服务器上,一次在客户端上。不是这样吗?
2021-04-04 16:43:21

据 reactjs.org 称,将来将不支持 componentWillMount。 https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

无需使用 componentWillMount。

如果你想在组件挂载之前做一些事情,只需在constructor()中做。

如果要做网络请求,就不要在componentWillMount里做。这是因为这样做会导致意想不到的错误。

网络请求可以在 componentDidMount 中完成。

希望能帮助到你。


更新于 08/03/2019

你要求 componentWillMount 的原因可能是因为你想在渲染之前初始化状态。

只需在 useState 中执行即可。

const helloWorld=()=>{
    const [value,setValue]=useState(0) //initialize your state here
    return <p>{value}</p>
}
export default helloWorld;

或者您可能想在 componentWillMount 中运行一个函数,例如,如果您的原始代码如下所示:

componentWillMount(){
  console.log('componentWillMount')
}

使用钩子,您需要做的就是删除生命周期方法:

const hookComponent=()=>{
    console.log('componentWillMount')
    return <p>you have transfered componeWillMount from class component into hook </p>
}

我只想在关于 useEffect 的第一个答案中添加一些内容。

useEffect(()=>{})

useEffect 在每次渲染上运行,它是 componentDidUpdate、componentDidMount 和 ComponentWillUnmount 的组合。

 useEffect(()=>{},[])

如果我们在 useEffect 中添加一个空数组,它只会在组件安装时运行。这是因为 useEffect 会比较你传递给它的数组。所以它不一定是一个空数组。它可以是没有改变的数组。例如,它可以是 [1,2,3] 或 ['1,2']。useEffect 仍然只在组件安装时运行。

这取决于您是希望它只运行一次还是在每次渲染后运行。只要您知道自己在做什么,如果您忘记添加数组,这并不危险。

我为钩子创建了一个示例。请检查一下。

https://codesandbox.io/s/kw6xj153wr


21/08/2019 更新

自从我写了上面的答案已经有一段时间了。我认为你需要注意一些事情。当你使用

useEffect(()=>{},[])

当react比较您传递给数组 [] 的值时,它用于Object.is()比较。如果你传递一个对象给它,比如

useEffect(()=>{},[{name:'Tom'}])

这与以下内容完全相同:

useEffect(()=>{})

每次都会重新渲染,因为当Object.is()比较一个对象时,它比较的是它的引用,而不是值本身。这与{}==={} 返回false 的原因相同,因为它们的引用不同。如果您仍然想比较对象本身而不是引用,您可以执行以下操作:

useEffect(()=>{},[JSON.stringify({name:'Tom'})])

2021 年 7 月 9 日更新:

关于依赖项的一些更新:

一般来说,如果你使用一个函数或一个对象作为依赖,它总是会重新渲染。但是 react 已经为你提供了解决方案:useCallback 和 useMemo

useCallback 能够记住一个函数。useMemo 能够记住一个对象。

看这篇文章:

https://javascript.plainenglish.io/5-useeffect-infinite-loop-patterns-2dc9d45a253f

当然,这应该是公认的答案 - 它解释了 ComponentWillMount 在钩子范例中不可用。功能组件中的初始化被简化 - 它只需要成为功能的一部分
2021-03-14 16:43:21
但是你不需要用钩子来实现它,因为它不会被支持。无需学习如何使用钩子来做到这一点。
2021-03-15 16:43:21
既然您已经提到 componentDidMount 是要使用的正确生命周期,您可以在答案中添加如何实现它,然后您的答案将比接受的答案更有意义
2021-03-18 16:43:21
这与 componentWillMount 有何相同之处?如果您将代码放入功能组件中,那么它将运行每个渲染,而不仅仅是在组件即将安装时。
2021-03-18 16:43:21
问题是如何用钩子实现它
2021-03-20 16:43:21

您可以破解 useMemo 钩子来模拟 componentWillMount 生命周期事件。做就是了:

const Component = () => {
   useMemo(() => {
     // componentWillMount events
   },[]);
   useEffect(() => {
     // componentDidMount events
     return () => {
       // componentWillUnmount events
     }
   }, []);
};

您需要在与您的状态交互的任何内容之前保留 useMemo 挂钩。这不是它的意图,但它对我所有 componentWillMount 问题都有效。

这是有效的,因为 useMemo 不需要实际返回一个值,您实际上不必将它用作任何东西,但是因为它记住了一个基于依赖项的值,该依赖项只会运行一次(“[]”)并且它位于我们的组件之上当组件在其他任何事情之前安装时运行一次。

这可能适用于当前的实现,但 React 文档明确指出不要这样做。您可以依赖 useMemo 作为性能优化,而不是语义保证。 reactjs.org/docs/hooks-reference.html#usememo
2021-03-27 16:43:21
我同意。这有点冒险,但如果你小心使用它,你可以得到你想要的。我发现它对于初始化独立于组件渲染状态的东西很有用。
2021-04-10 16:43:21
杰出的!谢谢!
2021-04-12 16:43:21

钩子中的 React Lifecycle 方法

为了简单的视觉参考,请遵循此图像

在此处输入图片说明

正如您在上图中可以简单地看到,对于 ComponentWillUnmount,您必须这样做

 useEffect(() => {
    return () => {
        console.log('componentWillUnmount');
    };
   }, []);
谢谢!你能把原始文章/帖子的链接放在这里吗?图片质量不好 [картинка шакального качества]。
2021-04-02 16:43:21