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

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

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


当前回答

钩子中的React生命周期方法

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

正如您在上图中所看到的,对于ComponentWillUnmount,您必须这样做

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

其他回答

本·卡普的答案对我来说似乎是唯一有效的答案。

但由于我们使用的是函数式方法,另一种方法可以受益于闭包和HoC:

const InjectWillmount = function(Node, willMountCallback) {
  let isCalled = true;
  return function() {
    if (isCalled) {
      willMountCallback();
      isCalled = false;
    }
    return Node;
  };
};

然后使用它:

const YourNewComponent = InjectWillmount(<YourComponent />, () => {
  console.log("your pre-mount logic here");
});

根据reactjs.org的说法,componentWillMount在未来将不受支持。 https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

不需要使用componentWillMount。

如果你想在组件挂载之前执行一些操作,只需在构造函数()中执行即可。

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

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

希望能有所帮助。


2019年8月3日更新

你请求componentWillMount的原因可能是因为你想在呈现之前初始化状态。

就在我们的地盘上做吧。

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

或者你想在componentWillMount中运行一个函数,例如,如果你的原始代码看起来像这样:

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

使用hook,你所需要做的就是删除生命周期方法:

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仍然只在组件挂载时运行。

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

我为hook创建了一个示例。请查看一下。

https://codesandbox.io/s/kw6xj153wr


2019年8月21日更新

我写上面的答案已经有一段时间了。有件事我觉得你需要注意。 当你使用

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如何与React Hooks一起使用:

componentWillMount已弃用,被认为是遗留的。反应推荐:

通常,我们建议使用构造函数()来初始化状态。

现在,在Hook FAQ中,你会发现函数组件的类构造函数的等价是:

构造函数:函数组件不需要构造函数。你可以在useState调用中初始化这个状态。如果计算初始状态的开销很大,您可以将一个函数传递给useState。

componentWillMount的用法示例如下所示:

const MyComp = () => {
  const [state, setState] = useState(42) // set initial value directly in useState 
  const [state2, setState2] = useState(createInitVal) // call complex computation

  return <div>{state},{state2}</div>
};

const createInitVal = () => { /* ... complex computation or other logic */ return 42; };

这是我如何使用useRef钩子模拟函数组件中的构造函数的方式:

function Component(props) {
    const willMount = useRef(true);
    if (willMount.current) {
        console.log('This runs only once before rendering the component.');
        willMount.current = false;        
    }

    return (<h1>Meow world!</h1>);
}

下面是生命周期的例子:

function RenderLog(props) {
    console.log('Render log: ' + props.children);
    return (<>{props.children}</>);
}

function Component(props) {

    console.log('Body');
    const [count, setCount] = useState(0);
    const willMount = useRef(true);

    if (willMount.current) {
        console.log('First time load (it runs only once)');
        setCount(2);
        willMount.current = false;
    } else {
        console.log('Repeated load');
    }

    useEffect(() => {
        console.log('Component did mount (it runs only once)');
        return () => console.log('Component will unmount');
    }, []);

    useEffect(() => {
        console.log('Component did update');
    });

    useEffect(() => {
        console.log('Component will receive props');
    }, [count]);


    return (
        <>
        <h1>{count}</h1>
        <RenderLog>{count}</RenderLog>
        </>
    );
}
[Log] Body
[Log] First time load (it runs only once)
[Log] Body
[Log] Repeated load
[Log] Render log: 2
[Log] Component did mount (it runs only once)
[Log] Component did update
[Log] Component will receive props

当然,Class组件没有Body步骤,由于函数和类的概念不同,不可能进行1:1的模拟。

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

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

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

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

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

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

希望这能有所帮助。