React Run Effect Again if State Doesnt Change

And so you lot learned how to use React useState and how to emulate the traditional setState in a functional React component.

Simply now you might be scratching your head and asking yourself, "How do I emulate a React component lifecycle?"

Don't worry, in this commodity volition go over:

  • What is React useEffect
  • How to use React useEffect
  • How to replicate the componentDidMount lifecycle
  • How to replicate the componentWillUnmount lifecycle
  • How to create cocky-sufficient lawmaking for componentDidUpdate lifecycle

So if you're not familiar with how to use information technology, read a previous article that covers about it; Introduction to React hooks.

Come back when you lot're ready!

What is React useEffect?

React useEffect is a role that gets executed for 3 unlike React component lifecycles.

Those lifecycles are componentDidMount, componentDidUpdate, and componentWillUnmount lifecycles.

Basic usage of useEffect

React useState example
                      import React, { useState } from 'react';  const App = () => {   const [message, setMessage] = useState('Howdy there, how are you?');    return <h1>{message}</h1> };  export default App;                  

In the code instance above, I'grand using React useState to save a bulletin.

I'k so grabbing my country variable, message, and I'one thousand printing information technology to the screen.

React useState output example

Simply now I want to useEffect to change the bulletin a second afterward the component has mounted.

React useEffect and useState example
                      import React, { useState, useEffect } from 'react';  const App = () => {   const [message, setMessage] = useState('Hi there, how are yous?');    useEffect(() => {     panel.log('trigger use effect hook');      setTimeout(() => {       setMessage("I'm fine, thanks for asking.");     }, 1000)   })    render <h1>{bulletin}</h1> };  export default App;                  

I've imported useEffect from the React library and I've added my result under the useState line.

useEffect accepts a function equally it'due south first argument. This function handler will take care of whatever side effects you like when it gets run.

The office is a callback function afterwards one of the React component lifecycle has been triggered.

React useEffect output

Information technology worked! Only there's a problem. Take a look at the panel log. The consequence got triggered twice.

This beliefs is not optimal, because if you take multiple effects or accept new prop values being tossed from a parent component, it may trigger the event multiple times.

This may cause inconsistency, weird side-effects, or freezing your app from an infinite loop.

Let's optimize this code a niggling bit more than.

React useEffect: The componentDidMount hook

The goal now is to execute the setMessage function only on the componentDidMount lifecycle.

That way if the App component receives whatever new props or if the state changes, the effect won't exist triggered again.

Replicating React useEffect on componentDidMount
                      import React, { useState, useEffect } from 'react';  const App = () => {   const [bulletin, setMessage] = useState('Hi there, how are y'all?');    useEffect(() => {     console.log('trigger apply effect claw');      setTimeout(() => {       setMessage("I'chiliad fine, thanks for asking.");     }, 1000)   }, []);    return <h1>{message}</h1> };  export default App;                  

Tin you see the difference from the sometime case?

If you lot oasis't caught it yet, I added an empty array bracket ([]) as a second argument to the useEffect claw function.

If you take a look at the console log information technology only shows "trigger use upshot hook" once.

Here's an example output with some other console log message that says, "App component rendered," after the effect function.

The second console message should only execute when the render lifecycle gets triggered.

If nosotros take a expect at the console log again, we can see the society of the lifecycles that it went through.

  1. Rendered lifecycle
  2. componentDidMount lifecycle
  3. Rendered lifecycle

This is the normal behavior that you would meet in a traditional React course component.

Past running an empty array [] as a second argument, you lot're letting React know that your useEffect function doesn't depend on whatever values from props or state.

This will aid you avert the componentDidUpdate lifecycle.

React useEffect: The componentWillUnmount hook

I showed an example how to avoid a trigger from a componentDidUpdate lifecycle with useEffect.

But what if yous have code that needs to become cleared up on a componentWillUnmount cycle?

How do nosotros replicate a componentWillUnmount lifecycle?

P.S. this lifecycle is too known as, the cleanup in a React claw function.

In the adjacent example I will demonstrate a employ instance where you'll need to clean upwards your code when a component will unmount.

Body onResize event in React useEffect
                      const WindowWidthSize = () => {   const [windowWidthSize, setWindowWidthSize] = React.useState(0);    React.useEffect(() => {     function handleResize(eastward) {       const { width } = certificate.body.getBoundingClientRect();        setWindowWidthSize(Math.ceil(width));     }      window.addEventListener('resize', handleResize)   }, []);    return (     <h1>       The window size {windowWidthSize} pixels     </h1>   ) };                  

In the image above, I accept created a new function component chosen, WindowWidthSize.

The objective of this component is to impress out the width size of the electric current window.

Every bit y'all see tin see, I'm using useState to keep track of the width size.

And right below it I'1000 adding a window event listener on the resize event.

So every time the user resizes the browser, it volition get the new width, save it into state, and print out the new width size.

Show window width in React functional component

Okay, so here nosotros have another React component that uses the component WindowWidthSize, and it has a magical push button.

When a user clicks this magical push, the WindowWidthSize component will vanish before your eyes.

Groovy, the lawmaking works. And if yous run into on the bottom right there is a blue highlight section called Window.

The blue highlight shows the window outcome listener I have added.

When I click on the magical button, the WindowWidthSize component will no longer exist. Simply there's a small trouble.

The window effect listener is nonetheless lingering effectually.

Situations like these are bad because this is what causes memory leaks in your app.

And you don't want to be greedy with your customers limited bandwidth.

Let's apply the clean up technique that useEffect gives u.s., to get rid of this lingering window result.

Replicating componenWillUnmount with React useEffect. Remove event listener.
                      const WindowWidthSize = () => {   const [windowWidthSize, setWindowWidthSize] = React.useState(0);    React.useEffect(() => {     function handleResize(e) {       const { width } = document.body.getBoundingClientRect();        setWindowWidthSize(Math.ceil(width));     }      window.addEventListener('resize', handleResize);      return () => window.removeEventListener('resize', handleResize);   }, []);    return (     <h1>       The window size {windowWidthSize} pixels     </h1>   ) };                  

I added a render function inside the useEffect function.

And within the return function I'm removing the even listener that I originally added.

When a functional component united nations-mounts the logic inside the return function will get executed.

So think to make clean up your lawmaking if necessary past returning a function inside the useEffect part.

React useEffect: The componentWillUpdate hook

By default useEffect will trigger anytime an update happens to the React component.

This ways if the component receives new props from its parent component or even when you alter the state locally, the upshot will run again.

In case you need the effect to trigger on a componentDidUpdate lifecycle, you desire to try and make information technology as cocky-sufficient as possible.

If yous don't, you will run into an infinite loop of updates, and but run your computer hot.

Set counter in useEffect
                      const Counter = () => {   const [counter, setCounter] = React.useState(0);    React.useEffect(() => {     setCounter(c => c + 1);   }, []);    return (     <div fashion={{textAlign: 'eye'}}>       <h1>Counter: {counter}</h1>     </div>   ); };                  

Correct in a higher place is a elementary counter app. All it does is print a number to the user.

P.S. useState also accepts functions equally an argument. This might be a amend choice if you lot desire a more accurate representation of the previous data.

I want this counter to increase on every second.

Increment counter every second in React useEffect
                      const Counter = () => {   const [counter, setCounter] = React.useState(0);    React.useEffect(() => {     const s = setInterval(() => {       setCounter(c => c + one);     }, 1000);   }, []);    return (     <div fashion={{textAlign: 'center'}}>       <h1>Counter: {counter}</h1>     </div>   ); };                  
React counter output

This is good, merely not skilful enough!

If yous take multiple setStates inside this component or fifty-fifty receiving new props, this tin can throw the useEffect hook off track.

Causing your app to not be synchronized or just freeze.

Replicating componentDidUpdate with React useEffect
                      const Counter = () => {   const [counter, setCounter] = React.useState(0);    React.useEffect(() => {     const s = setInterval(() => {       setCounter(c => c + one);     }, 1000);      render () => clearInterval(s);   }, [counter]);    return (     <div manner={{textAlign: 'eye'}}>       <h1>Counter: {counter}</h1>     </div>   ); };                  

Now it'south more self-sufficient.

One, I've added a clean up office to clear the interval whenever the component volition unmount.

Two, I've added the counter variable inside the array subclass that's institute in the 2nd argument of the useEffect function.

This tells React to only trigger the effect when counter is a dissimilar value.

If counter has not changed in value, the upshot won't execute.

This is helpful because you lot tin safely add together multiple useEffects, setStates, or even laissez passer down new prop values, and it won't desynchronize your counter component.

Using Async and Await in React useEffect

React.useEffect does Non permit you to add async in the callback function.

                      // This will cause your React awarding to pause! React.useEffect(async() => {   // ... stuff }, []);                  

React is expecting a regular function and non a promise.

But if yous'd like to utilize async/await you can motility your code into its own function, and invoke it within React.useEffect().

                      async role fetchCats() {   try {     const response = await fetch('url/to/cat/api');     const { cats } = await response.json();     console.log(cats) // [ { name: 'Mr. Whiskers' }, ...cats ]   } catch(e) {     panel.fault(due east);   } }  React.useEffect(() => {   fetchCats(); }, []);                  

Conclusion

React.useEffect is a basic hook that gets triggered on a combination of 3 React component lifecycles:

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

If you're planning to use React hooks y'all must know how to execute your effect on the right time.

Otherwise you might run across some issues for your users.

I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!

wardwhouners.blogspot.com

Source: https://linguinecode.com/post/getting-started-with-react-useeffect

Belum ada Komentar untuk "React Run Effect Again if State Doesnt Change"

Posting Komentar

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel