426

In the official docs of React it mentions -

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

My question is - how can we use the componentWillMount() lifecyle method in a hook?

Abrar
  • 6,874
  • 9
  • 28
  • 41

21 Answers21

739

You cannot use any of the existing lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount etc.) in a hook. They can only be used in class components. And with Hooks you can only use in functional components. The line below comes from the React doc:

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

suggest is, you can mimic these lifecycle method from class component in a functional components.

Code inside componentDidMount run once when the component is mounted. useEffect hook equivalent for this behaviour is

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

Notice the second parameter here (empty array). This will run only once.

Without the second parameter the useEffect hook will be called on every render of the component which can be dangerous.

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

componentWillUnmount is use for cleanup (like removing event listeners, cancel the timer etc). Say you are adding a event listener in componentDidMount and removing it in componentWillUnmount as below.

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

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

Hook equivalent of above code will be as follows

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

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])
NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
Bhaskar Gyan Vardhan
  • 9,057
  • 2
  • 18
  • 18
  • 416
    Nice explanation for other Lifecycle events, but this doesn't the question specifically about an alternative to componentWillMount(). – Shiraz May 15 '19 at 12:56
  • 3
    In the PanResponder examples I've seen componentWillMount seems to be required, otherwise you get undefined panHandlers. – Dror Bar Jul 15 '19 at 09:52
  • 1
    Note the `[]` as the second argument to `useEffect`. Without it, you end up with the effect being ran on every render, not just the first render. Since `[]` is the same every time, React thinks the effect has been applied already (read: dynamic programming/memoization at play), and doesn't re-run your function. – Nate Symer Aug 28 '19 at 17:15
  • And what if we do not need componentDidMount and would like just need to use componentWillUnmount alternative in functional component? – jake-ferguson Aug 29 '19 at 08:31
  • 4
    I now really understand the `useEffect()` function, thanks. – Iharob Al Asimi Sep 03 '19 at 19:07
  • Thank you this helped me cleanup an image slider component that used setInterval to change the slides. It needed to clearInterval on component dismount. – StefanBob Sep 30 '19 at 19:42
  • 206
    Why is this an accepted answer?? You didn't mention a hook equivalent for `componentWillMount` – Mykybo Nov 04 '19 at 12:51
  • 2
    Those who say that he didn't mention "componentWillUnmount" equivalent aren't paying attention, specifically to the "return" statement of the useEffect hook, which is where you can do all the 'unmounting' related tasks – techexpert Feb 23 '20 at 22:52
  • 46
    @techexpert The question asked for an equivalent to `componentWillMount`, not `componentWillUnmount`. This answer indeed does not answer the question at all, and just re-iterates what the OP already implied to know. – JoshuaCWebDeveloper Feb 24 '20 at 05:42
  • 1
    In case I use the last option, the empty array, what do I do if I want to read a state but it keeps complaining that I should add it to the dependency array? I want only to run the code when the component is unmounting. – sepha Feb 26 '20 at 09:06
  • @JoshuaCWebDeveloper ..I see, my mistake. But either way componentWillMount was deprecated back in 2018. You can do just about any initialization and other calculations in the function component before the return() statement.. The same thing as you can do in the class constructor. Makes componentWillMount somewhat redundant, imo – techexpert Mar 04 '20 at 01:10
  • 3
    @techexpert Actually, any code in a function component before the return statement will in fact be executed _every_ time the component is rendered, _not_ just the first time as the constructor (or previously `componentWillMount`) would be used for. @Ben Carp's answer is the highest voted answer that actually answers the question. – JoshuaCWebDeveloper Mar 08 '20 at 02:37
  • this answer is MUCH better than the many silly articles out there. Thank you so very much for the concise answer. – Bryan Jyh Herng Chong Mar 25 '20 at 02:55
  • 1
    I think the event handler for 'mousmove' defined in the remove and addEvent part are different due to ()=>{} creating 2 different function references. Hence that might cause a bug. – Biboswan Apr 15 '20 at 10:03
  • sometime we need to set a state in componentWillMount, without this, it will cost the component render twice, especially if u are running many layer component, u will render twice for all component, if u cant use componentWillMount on the top layer (assume you need) – user192344 Apr 29 '20 at 12:19
  • 1
    Ironically, I found this when looking for info about a hook version of `componentWillUnmount`, even though the original question is about `componentWillMount`. So, while it is a useful answer for me, this does not answer the original question. Not sure why this is the accepted answer, or why it has so many up-votes. – mbd Jul 01 '21 at 22:46
  • 2
    For people looking for an actual answer to the question that was asked, see https://stackoverflow.com/questions/53464595/how-to-use-componentwillmount-in-react-hooks/67315083#67315083 or the blog post https://dev.to/video/the-equivalent-of-componentwillmount-using-react-hooks-11em, since using useEffect very much is NOT equivalent to componentWillMount. – martinstark Dec 09 '22 at 11:24
247

useComponentWillMount hook

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

    if (willMount.current) cb()

    willMount.current = false
}

This hook could be a saver when there is an issue of sequence (such as running before another script). If that isn't the case, use useComnponentDidMount which is more aligned with React hooks paradigm.

useComponentDidMount hook

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

If you know your effect should only run once at the beginning use this solution. It will run only once after component has mounted.

useEffect paradigm

Class components have lifecycle methods which are defined as points in the timeline of the component. Hooks don't follow this paradigm. Instead effects should be structured by their content.

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

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

  ...
}

In the example above the effect deals with fetching the content of a post. Instead of a certain point in time it has a value it is dependent on - postID. Every time postID gets a new value (including initialization) it will rerun.

Component Will Mount discussion

In class components componentWillMount is considered legacy (source 1, source2). It's legacy since it might run more than once, and there is an alternative - using the constructor. Those considerations aren't relevant for a functional component.

Ben Carp
  • 24,214
  • 9
  • 60
  • 72
  • 65
    This is the only answer that answers the question and makes sense. Thank you! – chumakoff Jul 25 '19 at 13:16
  • 4
    The only problem with that is you get an extra render because of the state update involved. By using a ref instead you get the desired behavior without the extra render: ` const useComponentWillMount = func => { const willMount = useRef(true); useEffect(() => { willMount.current = false; }, []); if (willMount.current) { func(); } }; ` – remix23 Aug 15 '19 at 13:26
  • 4
    This functional implementation of `componentWillMount` based on `useEffect` has two problems. The first one is that there isn't a mounting lifecycle in functional components, both hooks will run after the component has rendered, so `Runs only once before component mounts` is misleading. The second one is that `componentWillMount` is called on server rendering and `useEffect` is not. Many libraries still rely on [`UNSAFE_componentWillMount`](https://reactjs.org/docs/react-component.html#unsafe_componentwillmount) because currently it's the only way to trigger a side-effect server-side. – Paolo Moretti Sep 05 '19 at 10:28
  • 3
    @PaoloMoretti, thanks. This componentWillMount hook, isn't the exact equivalent of componentWillMount lifecycle in a class component. However, the function that is passed to it, will run immediately, only the first time it is called. This practially means it will run before it is rendered, and before it even returns a value for the first time. Can we agree about that? I agree that using the name componentWillMount isn't ideal, since this name carries certain meaning from the class lifecycle version. Perhaps I better call it "useRunPreMount". – Ben Carp Sep 05 '19 at 10:49
  • 1
    I'm, sorry I actually didn't realize that the `useComponentWillMount ` callback runs on the first invocation. In that case, what I said about the first problem is wrong, I think it's possibly the closest implementation of `componentWillMount` with hooks. The second problem is still valid, because `useEffect` does not run in SSR, so I think it will always execute the callback, since `willMount.current` won't be set to `false` by `useEffect`. – Paolo Moretti Sep 05 '19 at 13:13
  • 1
    @PaoloMoretti, I don't quite get it. I don't work with SSR, but my undertstanding is that on SSR componentWillMount runs twice - once on the server and once on the client. I think the same is true for the callback that is passed to useComponentDidMount. useComponentDidMount relays on useEffect to stop invocing the callback. Until useEffect's callback is executed the component's function will run twice - once on the server and once on the client. Isn't that the case? – Ben Carp Sep 05 '19 at 16:24
  • Thank you for these snippets! These should be built in hooks to React. The semantic advantage of having hooks the easily describe what they are doing is still a void left in the wake of leaving behind class components IMO. I think hooks and functional components are the way to go no doubt, but the useEffect equivalent of componentDidMount is ugly and unless someone knows React well, will be confusing. The React team should have included something similar to this! – Matthew Goodwin Nov 12 '19 at 19:24
  • I agree that this is the only correct answer to the question. My use case was wanting to do a one-time pre-render action. Using `useRef` will indeed accomplish this (as will the custom ref provided here). Thank you! – JoshuaCWebDeveloper Feb 24 '20 at 05:48
  • Only one thing. I would use the intended function `useState` for storing values instead of `useRef` which is intended for referencing the DOM of a component. – Jiri Mihal Mar 26 '20 at 12:19
  • @JiriMihal see remix23 comment above. Originally I used useState and remix23 suggested useRef. I think he has a point. I think useRef is intended for dom references, but not only for this purpose. – Ben Carp Mar 26 '20 at 16:48
  • @BenCarp I see it, it makes sense. I noticed one more thing. `willMount.current = false;` should be right after `func();`. If `func();` changes component state, you will get an infinite loop. – Jiri Mihal Mar 26 '20 at 19:41
  • @JiriMihal, Nice catch. Thx! I fixed my answer. Luckily, such a situation is noticeable (if someone passes a callback that updates state an infinite loop must occur and an error will show) and therefor isn't likely to get to production. – Ben Carp Apr 09 '20 at 06:46
  • 1
    @BenCarp, thank you so much for the the explanation and demo. I've been looking for an answer to componentWillMount implementation using hooks and your's works perfectly. :) – Muntasir Jul 22 '20 at 19:00
  • What would happen if you implement the useComponentWillMount hook with useMemo instead of useEffect ?? – norman123123 Sep 25 '20 at 21:54
  • @norman123123, As far as I can tell it will work exactly the same. – Ben Carp Sep 26 '20 at 03:24
  • Your `useRef` example is great, but the React docs specifically say not to use `useMemo` for this purpose. **You may rely on `useMemo` as a performance optimization, not as a semantic guarantee.** reactjs.org/docs/hooks-reference.html#usememo – Naliba May 25 '21 at 17:50
75

According to reactjs.org, componentWillMount will not be supported in the future. https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

There is no need to use componentWillMount.

If you want to do something before the component mounted, just do it in the constructor().

If you want to do network requests, do not do it in componentWillMount. It is because doing this will lead to unexpected bugs.

Network requests can be done in componentDidMount.

Hope it helps.


updated on 08/03/2019

The reason why you ask for componentWillMount is probably because you want to initialize the state before renders.

Just do it in useState.

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

or maybe You want to run a function in componentWillMount, for example, if your original code looks like this:

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

with hook, all you need to do is to remove the lifecycle method:

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

I just want to add something to the first answer about useEffect.

useEffect(()=>{})

useEffect runs on every render, it is a combination of componentDidUpdate, componentDidMount and ComponentWillUnmount.

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

If we add an empty array in useEffect it runs just when the component mounted. It is because useEffect will compare the array you passed to it. So it does not have to be an empty array.It can be array that is not changing. For example, it can be [1,2,3] or ['1,2']. useEffect still only runs when component mounted.

It depends on you whether you want it to run just once or runs after every render. It is not dangerous if you forgot to add an array as long as you know what you are doing.

I created a sample for hook. Please check it out.

https://codesandbox.io/s/kw6xj153wr


updated on 21/08/2019

It has been a while since I wrote the above answer. There is something that I think you need to pay attention to. When you use

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

When react compares the values you passed to the array [], it uses Object.is() to compare. If you pass an object to it, such as

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

This is exactly the same as:

useEffect(()=>{})

It will re-render every time because when Object.is() compares an object, it compares its reference, not the value itself. It is the same as why {}==={} returns false because their references are different. If you still want to compare the object itself not the reference, you can do something like this:

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

Update on 7/09/2021:

A few updates about the dependency:

Generally speaking, if you use a function or an object as a dependency, it will always re-render. But react already provides you with the solution: useCallback and useMemo

useCallback is able to memorize a function. useMemo is able to memorize an object.

See this article:

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

MING WU
  • 2,962
  • 1
  • 12
  • 16
  • 32
    and the question was how to implement it with hooks – Shubham Khatri Nov 26 '18 at 13:27
  • 5
    but you do not need to implement it with hooks because it will not be supported. No need to learn how to do that with hooks. – MING WU Nov 27 '18 at 03:01
  • 1
    Now that you have mentioned that componentDidMount is the correct lifecycle to use, you could have added how to implement that in your answer and then your answer would make more sense than the accepted answer – Shubham Khatri Nov 27 '18 at 05:19
  • that is right. Thanks for pointing it out. I will add it later this week. – MING WU Nov 27 '18 at 07:37
  • 10
    Surely this should be the accepted answer - it explains that ComponentWillMount is not available in the hooks paradigm. Initialisation in functional components is simplified - it just needs to be part of the function – Shiraz May 15 '19 at 12:58
  • 5
    How is this the same thing as componentWillMount? If you throw code into the functional component then it will run every single render, not only when the component is about to mount. – Overcode Jan 26 '20 at 20:32
32

React Lifecycle methods in hooks

for simple visual reference follow this image

enter image description here

As you can simply see in the above picture that for ComponentWillUnmount, you have to do like this

 useEffect(() => {
    return () => {
        console.log('componentWillUnmount');
    };
   }, []);
lokender singh
  • 829
  • 9
  • 18
27

You can hack the useMemo hook to imitate a componentWillMount lifecycle event. Just do:

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

You would need to keep the useMemo hook before anything that interacts with your state. This is not how it is intended but it worked for me for all componentWillMount issues.

This works because useMemo doesnt require to actually return a value and you dont have to actually use it as anything, but since it memorizes a value based on dependencies which will only run once ("[]") and its on top of our component it runs once when the component mounts before anything else.

Jan-Philipp Marks
  • 1,419
  • 8
  • 13
  • 6
    This might work with the current implementation, but the React docs specifically say not to do this. **You may rely on useMemo as a performance optimization, not as a semantic guarantee.** https://reactjs.org/docs/hooks-reference.html#usememo – Naliba May 25 '21 at 15:28
  • I agree. It's slightly risky, but if you use it carefully you can get what you are looking for. I find it useful for initializing things that are independent from the components rendering status. – Jan-Philipp Marks Jun 15 '21 at 06:09
23

useLayoutEffect could accomplish this with an empty set of observers ([]) if the functionality is actually similar to componentWillMount -- it will run before the first content gets to the DOM -- though there are actually two updates but they are synchronous before drawing to the screen.

for example:


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

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

The benefit over useState with an initializer/setter or useEffect is though it may compute a render pass, there are no actual re-renders to the DOM that a user will notice, and it is run before the first noticable render, which is not the case for useEffect. The downside is of course a slight delay in your first render since a check/update has to happen before painting to screen. It really does depend on your use-case, though.

I think personally, useMemo is fine in some niche cases where you need to do something heavy -- as long as you keep in mind it is the exception vs the norm.

rob2d
  • 964
  • 9
  • 16
  • 5
    useLayoutEffect is the way to go!!!! This answer my question regarding checking if the user is logged in. (The problem was, the components would load, then check if user is logged in.) My question is though, is this standard practice? I'm not seeing at too many places – Jessica May 16 '19 at 19:11
  • 1
    yeah it's pretty common; mentioned in official React docs as well -- just in smaller text because of the ramifications of double DOM render in order to run logic before a user notices. – rob2d Jun 17 '19 at 16:04
  • 1
    Actually it runs after rendering the component. So it's totally different than componentWillMount. – Jiri Mihal Mar 26 '20 at 12:08
  • As @JiriMihal mentioned, `useLayoutEffect` runs after rendering, from React Docs (https://reactjs.org/docs/hooks-reference.html#uselayouteffect): `If you’re migrating code from a class component, note useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate.` – yorch Feb 11 '22 at 06:13
21

This is the way how I simulate constructor in functional components using the useRef hook:

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>);
}

Here is the lifecycle example:

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

Of course Class components don't have Body steps, it's not possible to make 1:1 simulation due to different concepts of functions and classes.

Jiri Mihal
  • 432
  • 3
  • 11
7

I wrote a custom hook that will run a function once before first render.

useBeforeFirstRender.js

import { useState, useEffect } from 'react'

export default (fun) => {
  const [hasRendered, setHasRendered] = useState(false)

  useEffect(() => setHasRendered(true), [hasRendered])

  if (!hasRendered) {
    fun()
  }
}

Usage:

import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'


export default () => { 
  useBeforeFirstRender(() => {
    console.log('Do stuff here')
  })

  return (
    <div>
      My component
    </div>
  )
}
Littletime
  • 527
  • 6
  • 12
4

Given that

  • componentWillMount is deprecated (1, 2, 3), and that the suggested replacement is executing code in the constructor
  • in a functional component, code executed before the return statement is implicitly run before rendering it
  • the rough equivalent of mounting a class component is the initial call of a functional component
  • the goal is to execute a piece of code once, before the DOM ui is updated, and never run the code again for as long as the component remains "mounted"

The solution would be

Running a function in the body of the functional component only once. Since code in the body of a functional component is normally run on every re-render, we need to turn to hooks. The options are useState, useMemo, or useEffect, depending on the timing required for the use case.

Since the code needs to run before the initial render is committed to the screen, this disqualifies useEffect: “The function passed to useEffect will run after the render is committed to the screen.” 4.

Since we want to guarantee that the code will only run once and not be recalculated, this disqualifies useMemo: "In the future, React may choose to “forget” some previously memoized values and recalculate them on next render" 5.

useState supports lazy initial state calculations that are guaranteed to run only once when a functional component is first rendered, which is exactly what we're looking for.

Example with useState

const runOnceBeforeRender = () => {};

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

  return (<></>);
}

As a custom hook

const runOnceBeforeRender = () => {};

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

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

  return (<></>);
};

The runOnceBeforeRender function can optionally return a value that will be available immediately upon the first render of the function, triggering no re-renders. The value won't be recalculated on subsequent renders.

const runOnceBeforeRender = () => 1 + 1;

const useOnInitialRender = (fn) => {
  const [value] = useState(fn);

  return value;
}

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

  return (<>{value}</>); // 2
};

A (probably unnecessary) NPM package: useOnce hook

martinstark
  • 187
  • 8
1

Ben Carp's answer seems like only valid one to me.

But since we are using functional ways just another approach can be benefiting from closure and HoC:

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

Then use it :

const YourNewComponent = InjectWillmount(<YourComponent />, () => {
  console.log("your pre-mount logic here");
});
Kerem atam
  • 2,387
  • 22
  • 34
1

It might be clear for most, but have in mind that a function called inside the function component's body, acts as a beforeRender. This doesn't answer the question of running code on ComponentWillMount (before the first render) but since it is related and might help others I'm leaving it here.

const MyComponent = () => {
  const [counter, setCounter] = useState(0)
  
  useEffect(() => {
    console.log('after render')
  })

  const iterate = () => {
    setCounter(prevCounter => prevCounter+1)
  }

  const beforeRender = () => {
    console.log('before render')
  }

  beforeRender()

  return (
    <div>
      <div>{counter}</div>
      <button onClick={iterate}>Re-render</button>
    </div>
  )
}

export default MyComponent
dimyG
  • 687
  • 9
  • 19
0

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

Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.

  • usememo is for performance optimization. A hook will be rendered again after being already mounted if a prop change, which defeat the purpose of the author. – max54 May 23 '19 at 15:26
  • A hook does not render, a hook will cause a component to re-render. Hooks are also not dependent on props, they are simply tools to manage state and component lifecycle events using side effects. – Shah Aug 26 '21 at 19:39
0

There is a nice workaround to implement componentDidMount and componentWillUnmount with useEffect.

Based on the documentation, useEffect can return a "cleanup" function. this function will not be invoked on the first useEffect call, only on subsequent calls.

Therefore, if we use the useEffect hook with no dependencies at all, the hook will be called only when the component is mounted and the "cleanup" function is called when the component is unmounted.

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

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

The cleanup return function call is invoked only when the component is unmounted.

Hope this helps.

AfikDeri
  • 2,069
  • 17
  • 19
  • 6
    How does this help if it has nothing to do with *componentWillMount*? Am I missing something? – ZenVentzi Nov 13 '19 at 17:53
  • Yes, you are missing the fact that in the same `useEffect` call you get the same functionality of `componentWillMount` and `componentWillUnmount` in a nice and clean way – AfikDeri Nov 18 '19 at 11:19
  • That's not true, `useEffect` only runs after a render while `componentWillMount` runs before the component renders. – Overcode Jan 26 '20 at 20:34
  • 1
    @Overcode I was talking about `componentDidMount` not `componentWillMount`. I missed that in the question, my bad. – AfikDeri Jan 27 '20 at 12:21
0

Short answer to your original question, how componentWillMount can be used with React Hooks:

componentWillMount is deprecated and considered legacy. React recommendation:

Generally, we recommend using the constructor() instead for initializing state.

Now in the Hook FAQ you find out, what the equivalent of a class constructor for function components is:

constructor: Function components don’t need a constructor. You can initialize the state in the useState call. If computing the initial state is expensive, you can pass a function to useState.

So a usage example of componentWillMount looks like this:

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; };
ford04
  • 66,267
  • 20
  • 199
  • 171
0

As it has been stated in react document:

You might be thinking that we’d need a separate effect to perform the cleanup. But code for adding and removing a subscription is so tightly related that useEffect is designed to keep it together. If your effect returns a function, React will run it when it is time to clean up:

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';
}

so the only thing that we need to have the componentWillUnmount in hooks is to return a function inside a useEffect, as explained above.

Saba
  • 376
  • 5
  • 19
0

So for React hooks, I think declaring your logic before the return statement can work. You should have a state that is set to true by default. In my case, I called the state componentWillMount. Then a conditional to run a block of code when this state is true (the block of code contains the logic you want executed in your componentWillMount), the last statement in this block should be resetting the componentWillMountState to false (This step is important because if it is not done, infinite rendering will occur) Example

// do your imports here

const App = () =>  {
  useEffect(() => {
    console.log('component did mount')
  }, [])
  const [count, setCount] = useState(0);
  const [componentWillMount, setComponentWillMount] = useState(true);
  if (componentWillMount) {
    console.log('component will mount')
    // the logic you want in the componentWillMount lifecycle
    setComponentWillMount(false)
  }
  
  return (
    <div>
      <div>
      <button onClick={() => setCount(count + 1)}> 
        press me
      </button>
      <p>
        {count}
      </p>
      
      </div>
    </div>
  )
}
Nature
  • 149
  • 1
  • 6
0

This might not be the exact alternative to the componentWillMount method but here is a method that can be used to achieve the same objective but by using useEffect :

First initialize the object where you retrive the data to an empty value and define the useEffect method:

const [details, setDetails] = useState("")

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

const retrieveData = () => {       
       getData()                  // get data from the server 
      .then(response => {
        console.log(response.data);
        setDetails(response.data)
      })
      .catch(e => {
        console.log(e);
      })
  }

Now in the JSX where we return add a terenary operator

*return(
  <div>
    { 
   details ? (
   <div class="">
   <p>add Your Jsx Here</p>
</div>
): (
  <div>
<h4>Content is still Loading.....</h4>
</div>
)
}
  </div>
)*

This will ensure that until the object 'details' has data in it the second part of the terenary operator is loaded which inturn triggers the useEffect method that leads to setting the data received from the server in the 'details' object, hence the rendering of the primary JSX

0

We recently had problem with this because we need to do something when a component will mount, that is we need to update the global state.

So I created this hook, not sure how good of an approach this is but so far it works as long as we use this sparingly and only for simple tasks. I probably would not use this for network requests and other long-running and complex tasks.

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;
aprilmintacpineda
  • 1,114
  • 13
  • 21
0

componentWillMount is deprecated (as mentioned in other comments), the reason for it I think it's very easy to be handled by a simple HOC.

const withComponentWillMount = (WrappedComponent, handler) => {
  return (props) => {
    return handler(props) ? <WrappedComponent {...props} /> : null;
  }
}

I usually implement this solution for my projects. With this HOC, if handler returned false, there is nothing run inside component, included hooks.

Leonardo
  • 111
  • 5
-1

React component is a function right? So just let componentWillMount moment be the function body before return statement.

function componentWillMountMomentIsHere() {
  console.log('component will mount')
}


function AnyComponent(){
  const [greeting, setGreeting] = useState('Hello')

  componentWillMountMomentIsHere()

  
  return <h1>{greeting}</h1>
}
-6

Just simply add an empty dependenncy array in useEffect it will works as componentDidMount.

useEffect(() => {
  // Your code here
  console.log("componentDidMount")
}, []);