DEV Community

Cover image for UseEffect: Is it really Effective?
Rajshekhar Yadav
Rajshekhar Yadav

Posted on • Edited on • Originally published at yadavrajshekhar.hashnode.dev

UseEffect: Is it really Effective?

What Are Hooks

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

What is useEffect

If you have been working with class component you would have performed side effects in your component like updating Ui, fetching data from api or subscribing to any changes. Since the render method is too early to perform side effects we have lifecycle method in class component.

  1. ComponentDidMount
  2. ComponentDidUpdate
  3. ComponentWillUnmount

You must have been concerned about how useEffect would handle all of this. Let's get started without further ado.

alright-then-jim-carrey.gif

How to use useEffect

UseEffect accept two arguments:

  • Callback: It is a function where we put write the side - effect logics.
  • Dependency : It is an optional array of dependency. Callback function got executed whenever these dependency changes.
  useEffect(() => {
  //Callback
  }, [dependencies]);
Enter fullscreen mode Exit fullscreen mode

Let's have a look at all of the scenarios with some examples:

  • When the dependency is not provided: This side-effect runs after every rendering.
  useEffect(() => {
    console.log('App.js: useEffect');
  });

  return (
    <SafeAreaView style={backgroundStyle}>
      <View>
        <Text style={styles.sectionTitle}>Hi There {count} times</Text>
        <Button
          title="Press me"
          onPress={() => {
            setCount(count + 1);
          }}
        />
      </View>
    </SafeAreaView>
  );
Enter fullscreen mode Exit fullscreen mode

If we check at the logs, we can see that the side-effect is called whenever the count changes.

 LOG  App.js: useEffect
 LOG  App.js: useEffect
 LOG  App.js: useEffect
 LOG  App.js: useEffect
Enter fullscreen mode Exit fullscreen mode
  • When the dependency array is empty: This side-effect will call first time only.
 useEffect(() => {
    console.log('App.js: useEffect');
  }, []);
Enter fullscreen mode Exit fullscreen mode

If we look into logs, side-effect got called only one time

 LOG  Click Me
 LOG  Click Me
 LOG  Click Me
 LOG  Click Me
Enter fullscreen mode Exit fullscreen mode

When configured in such a way, the useEffect() executes the callback just once, after initial mounting. We can say it will work like componentDidMount()

  • When the dependency array have some parameter: This side-effect runs whenever the parameter changes .
 const [count, setCount] = React.useState(0);
  const [countDown, setCountDown] = React.useState(100);
  useEffect(() => {
    console.log('App.js: useEffect');
  }, [count]);
  return (
    <SafeAreaView style={{flex:1}}>
      <View>
        <Text style={styles.sectionTitle}>Hi There {count} times</Text>
        <Text style={styles.sectionTitle}>Time is ticking {countDown}</Text>
        <Button
          title="Increment"
          onPress={() => {
            console.log('Increment Count');
            setCount(count + 1);
          }}
        />
        <Button
          title="Decrement"
          onPress={() => {
            console.log('Decrement Count');
            setCountDown(countDown - 1);
          }}
        />
      </View>
    </SafeAreaView>
  );
Enter fullscreen mode Exit fullscreen mode

If you closely look into console, You will find whenever the value of count changes, useEffect got called only then.

 LOG  App.js: useEffect
 LOG  Decrement Count
 LOG  Decrement Count
 LOG  Decrement Count
 LOG  Decrement Count
 LOG  Increment Count
 LOG  App.js: useEffect
 LOG  Increment Count
 LOG  App.js: useEffect
 LOG  Increment Count
 LOG  App.js: useEffect
Enter fullscreen mode Exit fullscreen mode

So you can see it will work the same way like ComponentDidUpdate work in class component

Now you must be thinking, what about side-effect cleanup? Class component has a separate method to deal with it.
tenor.com

  • Side-Effect Cleanup

Some side effects need a cleanup, like canceling any api call while un-mounting, closing connection or clearing timers.

We can achieve this by returning a cleanup function from
useEffect() callback
.

useEffect(() => {
  // This is your side-effect logic
  return function cleanup() {
    // Side-effect cleanup
  };
},[dependencies]);
Enter fullscreen mode Exit fullscreen mode

Cleanup works in following way:

  1. While mounting the component, useEffect() invokes the callback having the side-effect. cleanup function is not called.
  2. On later renderings, before invoking the next side-effect callback, useEffect() invokes the cleanup function from the previous side-effect execution, then runs the current side-effect.
  3. At the end, after unmounting the component, useEffect() invokes the cleanup function from the latest side-effect.

Let me show you some basic code to explain:

 const [count, setCount] = React.useState(0);
  useEffect(() => {
    console.log('App.js: useEffect');
    return function cleanup() {
      console.log('App.js: cleanup');
    };
  }, [count]);
  return (
    <SafeAreaView style={{flex: 1}}>
      <View>
        <Text style={styles.sectionTitle}>Hi There {count} times</Text>
        <Button
          title="Increment"
          onPress={() => {
            console.log('Increment Count');
            setCount(count + 1);
          }}
        />
      </View>
    </SafeAreaView>
  );
Enter fullscreen mode Exit fullscreen mode

If you look into the logs, cleanup function is getting called every time before invoking the next side-effect.

 LOG  App.js: useEffect
 LOG  Increment Count
 LOG  App.js: cleanup
 LOG  App.js: useEffect
 LOG  Increment Count
 LOG  App.js: cleanup
 LOG  App.js: useEffect
Enter fullscreen mode Exit fullscreen mode

Use case of useEffect()

  1. Updating Ui whenever the state changes.
  2. *When we want to perform any action once, especially when the app mount first time. We can prefer useEffect. *

    Let us consider an example , we want to fetch list of newsfeed while loading the newsfeed screen.

 const [newsFeed, setNewsFeed] = React.useState([]);
  async function fetchNewsFeed() {
    const response = await fetch('/employees');
    const newsFeedData = await response.json(response);
    setNewsFeed(newsFeedData);
  }

  useEffect(() => {    //  can not be async
    fetchNewsFeed(); // Can invoke async function
  }, []);
Enter fullscreen mode Exit fullscreen mode

Conclusion

  1. useEffect(callback, dependencies) is the hook that manages the side-effects in functional components.

    • Callback argument is a function to put the side-effect logic.
    • Dependencies is a list of dependencies of your side-effect: being props or state values.
  2. useEffect(callback, dependencies) invokes the callback after initial mounting, and on later renderings, if any value inside dependencies has changed.

  3. useEffect(callback, dependencies) can be used in following ways

    • initial mounting(ComponentDidMount),
    • Managing state changes (ComponentDidUpdate)
    • For side-effect cleanup (ComponentWillUnmount)

Related Link

  1. React-Hooks-Documentation
  2. Hooks-API-Reference

thanks.gif

I hope this post helped you understand the basic idea of useEffect(). Feel free to add your suggestions.
Follow me on Twitter.

Happy coding

Top comments (3)

Collapse
 
tanth1993 profile image
tanth1993

On later renderings, before invoking the next side-effect callback, useEffect() invokes the cleanup function from the previous side-effect execution, then runs the current side-effect. I think this statement is the most important thing in useEffect. People usually think cleanup function/ the return would only run when component will unmount.

Collapse
 
yadav_rajshekhar profile image
Rajshekhar Yadav • Edited

When I started working with it, I was also having the same misconception.

Collapse
 
booboboston profile image
Bobo Brussels

Cool!