Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Hooks and Component Lifecycle Equivalent

What are the equivalents of the componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle hooks using React hooks like useEffect?

like image 835
Yangshun Tay Avatar asked Nov 11 '18 22:11

Yangshun Tay


People also ask

What is the equivalent of the componentDidMount lifecycle method using React hooks?

React Hooks Equivalent of componentDidUpdate The equivalent of the componentDidUpdate lifecycle method is also the useEffect hook.

Can hooks replace lifecycle methods?

The useEffect Hook allows us to replace repetitive component lifecycle code. Essentially, a Hook is a special function that allows you to “hook into” React features. Hooks are a great solution if you've previously written a functional component and realize that you need to add state to it.

What is the equivalent hook for the lifecycle method componentDidMount () in a class component?

If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount , componentDidUpdate , and componentWillUnmount combined. There are two common kinds of side effects in React components: those that don't require cleanup, and those that do.

What React lifecycle methods can be replaced by the useEffect () hook?

In the React documentation, the basic explanation of the useEffect Hook is the following, “If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount , componentDidUpdate , and componentWillUnmount combined.”


2 Answers

componentDidMount

Pass an empty array as the second argument to useEffect() to run only the callback on mount only.

function ComponentDidMount() {    const [count, setCount] = React.useState(0);    React.useEffect(() => {      console.log('componentDidMount');    }, []);      return (      <div>        <p>componentDidMount: {count} times</p>        <button          onClick={() => {            setCount(count + 1);          }}        >          Click Me        </button>      </div>    );  }    ReactDOM.render(    <div>      <ComponentDidMount />    </div>,    document.querySelector("#app")  );
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>  <script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>    <div id="app"></div>

componentDidUpdate

componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render. useEffect runs on every render including the first. So if you want to have a strict equivalent as componentDidUpdate, you have to use useRef to determine if the component has been mounted once. If you want to be even stricter, use useLayoutEffect(), but it fires synchronously. In most cases, useEffect() should be sufficient.

This answer is inspired by Tholle, all credit goes to him.

function ComponentDidUpdate() {    const [count, setCount] = React.useState(0);      const isFirstUpdate = React.useRef(true);    React.useEffect(() => {      if (isFirstUpdate.current) {        isFirstUpdate.current = false;        return;      }        console.log('componentDidUpdate');    });      return (      <div>        <p>componentDidUpdate: {count} times</p>        <button          onClick={() => {            setCount(count + 1);          }}        >          Click Me        </button>      </div>    );  }    ReactDOM.render(    <ComponentDidUpdate />,    document.getElementById("app")  );
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>  <script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>    <div id="app"></div>

componentWillUnmount

Return a callback in useEffect's callback argument and it will be called before unmounting.

function ComponentWillUnmount() {    function ComponentWillUnmountInner(props) {      React.useEffect(() => {        return () => {          console.log('componentWillUnmount');        };      }, []);        return (        <div>          <p>componentWillUnmount</p>        </div>      );    }        const [count, setCount] = React.useState(0);      return (      <div>        {count % 2 === 0 ? (          <ComponentWillUnmountInner count={count} />        ) : (          <p>No component</p>        )}        <button          onClick={() => {            setCount(count + 1);          }}        >          Click Me        </button>      </div>    );  }    ReactDOM.render(    <div>      <ComponentWillUnmount />    </div>,    document.querySelector("#app")  );
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>  <script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>    <div id="app"></div>
like image 81
Yangshun Tay Avatar answered Sep 17 '22 13:09

Yangshun Tay


From React docs:

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

By that saying they mean:

componentDidMount is sort of useEffect(callback, [])

componentDidUpdate is sort of useEffect(callback, [dep1, dep2, ...]) - the array of deps tell React: "if one of the deps is change, run the callback after rendering".

componentDidMount + componentDidUpdate is sort of useEffect(callback)

componentWillUnmount is sort of the returned function from the callback:

useEffect(() => {      /* some code */     return () => {        /* some code to run when rerender or unmount */     } ) 

With the help of Dan Abramov's phrasing from his blog, and some additions of my own:

While you can use those hooks, it’s not an exact equivalent. Unlike componentDidMount and componentDidUpdate, it will capture props and state. So even inside the callbacks, you’ll see the props and state of the specific render (which means in componentDidMount the initial props and state). If you want to see “latest” something, you can write it to a ref. But there’s usually a simpler way to structure the code so that you don’t have to. The returned function which supposes to be alternative to componentWillUnmount also is not an exact equivalent, since the function will run every time the component will re-render and when the component will unmount. Keep in mind that the mental model for effects is different from component lifecycles, and trying to find their exact equivalents may confuse you more than help. To get productive, you need to “think in effects”, and their mental model is closer to implementing synchronization than to responding to lifecycle events.

Example from Dan's blog:

function Counter() {   const [count, setCount] = useState(0);    useEffect(() => {     setTimeout(() => {       console.log(`You clicked ${count} times`);     }, 3000);   });    return (     <div>       <p>You clicked {count} times</p>       <button onClick={() => setCount(count + 1)}>         Click me       </button>     </div>   ); } 

enter image description here

If we use the class implementation:

componentDidUpdate() {   setTimeout(() => {     console.log(`You clicked ${this.state.count} times`);   }, 3000); } 

enter image description here

this.state.count always points at the latest count rather than the one belonging to a particular render.

like image 30
Edan Chetrit Avatar answered Sep 17 '22 13:09

Edan Chetrit