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?
You cannot use any of the existing lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount etc.) in a hook.They can only be used in a class components. And Hooks you can only use in a functional components. What the below line 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 listners, cancel the timer etc). Say you are adding a event listner in componentDidMount and remvoing 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', () => {})
}
}, [])
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 white 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 a 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'})])
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.
useComponentDidMount hook
In most cases useComponentDidMount is the tool to use. It will run only once, after component has mounted(initial render).
const useComponentDidMount = func => useEffect(func, []);
useComponentWillMount
It is important to note that in class components componentWillMount is considered legacy. If you need code to run only once before component has mounted, you can use the constructor. More about it here. Since functional component doesn't have the equivelant of a constructor, using a hook to run code only once before component mounts might make sense in certain cases. You can achieve it with a custom hook.
const useComponentWillMount = func => {
const willMount = useRef(true);
if (willMount.current) {
func();
}
useComponentDidMount(() => {
willMount.current = false;
});
};
However, there is a pitfall. Don't use it to asynchronously set your state (e.x following a server request. As you might expect it to affect the initial rendering which it won't). Such cases should be handled with useComponentDidMount.
Demo
const Component = (props) => {
useComponentWillMount(() => console.log("Runs only once before component mounts"));
useComponentDidMount(() => console.log("Runs only once after component mounts"));
...
return (
<div>{...}</div>
);
}
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>
)
)
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.
来源:https://stackoverflow.com/questions/53464595/how-to-use-componentwillmount-in-react-hooks