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

如果你熟悉React类的生命周期方法,你可以思考 将useEffect钩子作为componentDidMount, componentDidUpdate和 componentWillUnmount总和。

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


当前回答

我们最近遇到了这个问题,因为我们需要在组件挂载时做一些事情,也就是我们需要更新全局状态。

所以我创建了这个钩子,不确定这个方法有多好,但到目前为止,只要我们少用它,只用于简单的任务,它就能工作。我可能不会将它用于网络请求和其他长时间运行的复杂任务。

import { useRef } from 'react';

function useComponentWillMount(callback: () => void) {
  const hasMounted = useRef(false);

  if (!hasMounted.current) {
    (() => {
      hasMounted.current = true;
      callback();
    })();
  }

  console.log(hasMounted.current);
  return null;
}

export default useComponentWillMount;

其他回答

有一个很好的解决方案来实现componentDidMount和componentWillUnmount与useEffect。

根据文档,useEffect可以返回一个“清理”函数。该函数不会在第一次useEffect调用时调用,只在后续调用时调用。

因此,如果我们使用useEffect钩子而没有任何依赖关系,那么该钩子只会在组件挂载时被调用,而“cleanup”函数则会在组件卸载时被调用。

useEffect(() => {
    console.log('componentDidMount');

    return () => {
        console.log('componentWillUnmount');
    };
}, []);

只有在卸载组件时才调用清理返回函数调用。

希望这能有所帮助。

useLayoutEffect可以用一个空的观察者集([])来完成这一点,如果功能实际上类似componentWillMount——它将在第一个内容到达DOM之前运行——尽管实际上有两个更新,但它们在绘制到屏幕之前是同步的。

例如:


function MyComponent({ ...andItsProps }) {
     useLayoutEffect(()=> {
          console.log('I am about to render!');
     },[]);

     return (<div>some content</div>);
}

与useState相比,使用初始化器/setter或useEffect的好处是,尽管它可以计算一个渲染传递,但用户不会注意到DOM的实际重新渲染,并且它是在第一次明显的渲染之前运行的,而useEffect则不是这样。缺点当然是在你的第一次渲染中有轻微的延迟,因为在绘制到屏幕之前必须进行检查/更新。不过,这确实取决于您的用例。

我个人认为,useMemo在一些特定的情况下是很好的,当你需要做一些沉重的事情时——只要你记住这是例外与规范。

https://reactjs.org/docs/hooks-reference.html#usememo

记住,传递给useMemo的函数在呈现期间运行。 不要在那里做渲染时通常不会做的事情。 例如,副作用属于useEffect,而不是useMemo。

正如react文档中所述:

您可能会认为我们需要一个单独的效果来执行 清理。但是添加和删除订阅的代码非常紧凑 useEffect的设计是为了将它们放在一起。如果你的效果 返回一个函数,React会在清理的时候运行它:

useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

所以我们唯一需要在钩子中使用componentWillUnmount的是在useEffect中返回一个函数,如上所述。

考虑到

componentWillMount已弃用(1,2,3),建议的替换是在构造函数中执行代码 在函数组件的return语句之前执行的代码在呈现之前隐式运行 与挂载类组件大致相当的是函数组件的初始调用 目标是在UI更新之前执行一些代码一次

解决办法是

在函数组件的主体中只运行一次函数。这可以通过useState、useMemo或useEffect来实现,具体取决于用例所需的时间。

由于代码需要在将初始呈现提交给屏幕之前运行,这将取消useEffect的资格,因为“传递给useEffect的函数将在将呈现提交给屏幕之后运行。”4。

因为我们想要保证代码只运行一次,这就使useMemo失去了资格,因为“在未来,React可能会选择“忘记”一些以前记住的值,并在下一次渲染时重新计算它们”5。

useState支持惰性初始状态计算,保证在初始渲染期间只运行一次,这似乎是一个很好的工作候选人。

useState的示例:

const runOnceBeforeRender = () => {};

const Component = () => {
  useState(runOnceBeforeRender);

  return (<></>);
}

作为自定义钩子:

const runOnceBeforeRender = () => {};

const useOnInitialRender = (fn) => {
  useState(fn);
}

const Component = () => {
  useOnInitialRender(runOnceBeforeRender);

  return (<></>);
};

runOnceBeforeRender函数可以选择返回一个在函数第一次呈现时立即可用的状态,不会触发重新呈现。

一个(可能不必要的)NPM包:useOnce钩子