panzerdp / dmitripavlutin.com-comments

7 stars 0 forks source link

/react-useeffect-explanation/ #87

Open panzerdp opened 4 years ago

panzerdp commented 4 years ago

Written on 10/10/2020 14:07:32

URL: https://dmitripavlutin.com/react-useeffect-explanation/

Storky commented 3 years ago

Hilarious, I have 1+ years of exp with hooks, especially useEffect looked absolutely discovered. And today I found, that return of useEffect's callback is not exact analogue of componentDidUnmount. Its just clean-up before re-use of the same effect.

Like on 8 interviews I answered that its the same as componentDidUnmount and nobody corrected me, maybe they are also were wrong...

panzerdp commented 3 years ago

Hilarious, I have 1+ years of exp with hooks, especially useEffect looked absolutely discovered. And today I found, that return of useEffect's callback is not exact analogue of componentDidUnmount. Its just clean-up before re-use of the same effect.

Like on 8 interviews I answered that its the same as componentDidUnmount and nobody corrected me, maybe they are also were wrong...

@Storky, I'm glad my post has helped you understand useEffect() better.

When trying to understand useEffect(), it's good to forget about the old lifecycle methods.

mayajp commented 3 years ago

Hi Dimitry, I read your article as a beginner it was a great help for me to understand the use of useEffect, thanks for your writing about it. Can you please explain a demo of how can we use useEffect for validating a form and afterword's submitting(if i am rite we have to use the callback for call this submission from useEffect ) a api call.

panzerdp commented 3 years ago

Hi Dimitry, I read your article as a beginner it was a great help for me to understand the use of useEffect, thanks for your writing about it. Can you please explain a demo of how can we use useEffect for validating a form and afterword's submitting(if i am rite we have to use the callback for call this submission from useEffect ) a api call.

@mayajp Take a look at this post regarding form submission.

Krakof commented 3 years ago

Hi Dmitri, Thanks a lot for the article. My question is more about a code style. Is it a good idea to wrap async func with useCallback like:

const fetchMethod = useCallback(async (id) => {
       //  fetching something
}, [id])

useEffect(() => fetchMethod(), [fetchMethod])

to keep the effect clean and simple. If I have an additional logic for fetched data(conversion, formatting), should I keep it in the same useEffect? Thanks in advance

panzerdp commented 3 years ago

Hi Dmitri, Thanks a lot for the article.

You're welcome @Krakof.

My question is more about a code style. Is it a good idea to wrap async func with useCallback like:

const fetchMethod = useCallback(async (id) => {
       //  fetching something
}, [id])

useEffect(() => fetchMethod(), [fetchMethod])

to keep the effect clean and simple. If I have an additional logic for fetched data(conversion, formatting), should I keep it in the same useEffect? Thanks in advance

Here are my considerations:

1) I would keep the code simple and skip the use of useCallback(). You can put the conversion and formatting logic inside of the useEffect():

useEffect(() => {
  const fetchMethod = async () => {
    // fetching logic
  };
  fetchMethod();
}, [id])

2) If you see the same fetching logic being shared between multiple components, you can extract the fetching into a custom hook. Extracting the side-effect logic out of the component makes the component simpler, as well conforms to the DRY (Don't Repeat Yourself) principle.

Krakof commented 3 years ago

@panzerdp Thanks a lot and Happy New Year!

mdasif114 commented 3 years ago

You made my day by explaining useEffect functionality clearly. Thank you so much!!!!!!!

panzerdp commented 3 years ago

You made my day by explaining useEffect functionality clearly. Thank you so much!!!!!!!

Glad you like it @mdasif114.

HeflerDev commented 3 years ago

Had to Sign-in just to write this thank you note. I'm having hard time understanding some basic React Concepts and this surely helped me a lot.

panzerdp commented 3 years ago

Had to Sign-in just to write this thank you note. I'm having hard time understanding some basic React Concepts and this surely helped me a lot.

Awesome @HeflerDev! If you have hard time understanding some other concepts of React, please let me know I might consider writing a post.

HeflerDev commented 3 years ago

No, I don't, by far as I know haha.

gabridb commented 3 years ago

I'm quite new to react and this is the best article I've ever read about this, really useful. Thank you very much for sharing!

panzerdp commented 3 years ago

I'm quite new to react and this is the best article I've ever read about this, really useful. Thank you very much for sharing!

You're welcome @gabridb!

Dron007 commented 3 years ago

Nice article. I am trying to understand is it required to call useEffect() in event handlers (form's onSubmit) or it's okay to use simple async functions for data fetching for example? I cannot understand why I need useEffect here. It works without it. But maybe I am missing some point.

export const useApiHook = () => {
  const [data, setData] = useState([])
  const [isLoading, setIsLoading] = useState(false)

  const apiCall = async (apiMethod, ...params) => {
    setIsLoading(true)
    const res = await apiMethod(...params)
    setIsLoading(false)
    return res
  }

  const request = async () => {
    const res = await apiCall(api.fetchMimeTypes)
    setData(Object.values(res.entities.mimeTypes))
  }

  const add = async (name) => {
    await apiCall(api.createMimeType, name)
    request()
  }

  ...

  return ({data, isLoading, request, add, edit, remove})
}

And in component:

function Page() {
  const { data, isLoading, request, add, edit, remove } = useApiHook()

  return (
    <AddModal
      onSubmit={add}
      ...
    />
    ...
  )
}
panzerdp commented 3 years ago

Nice article. I am trying to understand is it required to call useEffect() in event handlers (form's onSubmit)

If the request is started when the user submits the form, then you don't need useEffect().

If you need a fetch request on mounting to fill the form with initial data, then you need useEffect().

nykel commented 3 years ago

I arrived at your blog through google and i would like to congratulate you for this article. Your explanation was as if shells fell out of my eyes. I feel more motivated to program with React because I now correctly understand this important hook. Thanks!!!

panzerdp commented 3 years ago

I arrived at your blog through google and i would like to congratulate you for this article. Your explanation was as if shells fell out of my eyes. I feel more motivated to program with React because I now correctly understand this important hook. Thanks!!!

Thanks for the nice words @nykel!

chrisvwlc commented 3 years ago

Thank you for this post! I've read several others in the past 2 weeks about this hook, but none that helped me understand it nearly as well. Not sure about karma, but I hope this brings you good returns! Now I'm off to read your related posts... :-)

panzerdp commented 3 years ago

Thank you for this post! I've read several others in the past 2 weeks about this hook, but none that helped me understand it nearly as well. Not sure about karma, but I hope this brings you good returns! Now I'm off to read your related posts... :-)

Thanks @chrisvwlc! May your karma grow too!

sagarjanikmart commented 3 years ago

Nice article, cleared lot of concepts.

panzerdp commented 3 years ago

Nice article, cleared lot of concepts.

Thanks @sagarjanikmart!

Onoshe commented 3 years ago

Hello, thanks for this great piece. Am still trying to learn how to use "useEffect" hook. Please, I want to know what happens if the second argument (dependency) is left out completely, as in useEffect(callback), ie, no [ ]. Any side effect?

panzerdp commented 3 years ago

Hello, thanks for this great piece. Am still trying to learn how to use "useEffect" hook. Please, I want to know what happens if the second argument (dependency) is left out completely, as in useEffect(callback), ie, no [ ]. Any side effect?

It's mentioned in the post:

A) When dependencies array is Not provided: the side-effect runs after every rendering.

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Runs after EVERY rendering
  });  
}
ulvienzo commented 3 years ago

Hi, before all thank you for explanation, I get some gotcha points, but yet can not get the idea clearly. You said above:

A functional React component uses props and/or state to calculate the output. If the functional component makes calculations that don’t target the output value, then these calculations are named side-effects.

So, if our functional component returns simple output and did not make any calculation for output as below, which is not dependable any props/state, is this calculation still side effect?

const myFunc = ()=>

Hello

Mr-Vipi commented 3 years ago

I read the article. Everything was clear to me and well explained, but I still don't get something I'll try to explain this by example:

const MyComponent = () => {
  const [size, setSize] = useState(window.innerWidth);
  const checkSize = () => {
    setSize(window.innerWidth);
  };
  useEffect(() => {
    console.log("useEffect");
    window.addEventListener("resize", checkSize);
    document.title = `Window is ${size} PX`;
    // return () => {
    //   console.log("cleanUp");
    //   window.removeEventListener("resize", checkSize);
    // };
  }, []);
  console.log("render");
  return (
    <>
      <h1>window</h1>
      <h2>{size} PX</h2>
    </>
  );
};

In the example above, I have a component that checks for the window inner size I have the event listener as part of the callback passed in the useEffect Hook and the setSize() as part of the callback of the event listener. What I don't get is: since we have an empty list of dependencies as second parameter for my useEffect, how is possible that the size state changes everytime we change the window size:

  1. knowing that when we have an empty list of dependencies the useEffect callback is called only on the first render and
  2. knowing that the setSize() is inside the useEffect callback should be triggered once. I don't know if I made it through to explain what I dont get in this example. Thanks in advance who ever reads this message :)
panzerdp commented 3 years ago

knowing that the setSize() is inside the useEffect callback should be triggered once.

@Mr-Vipi That's not accurate.

1) setSize() is called by checkSize() event handler every time the window size changes (state update on event)

2) useEffect() after mounting just attaches the event handler to listen for events: window.addEventListener("resize", checkSize). (attaching event listener after mounting)

Mr-Vipi commented 3 years ago

Thanks for the reply, Dimitry, now it makes a lot more sense in my head. Since I'm still learning the react hooks I think I should take a look in more deep for the eventListeners too, the way how it works.

panzerdp commented 3 years ago

Thanks for the reply, Dimitry, now it makes a lot more sense in my head. Since I'm still learning the react hooks I think I should take a look in more deep for the eventListeners too, the way how it works.

You're welcome @Mr-Vipi.

If you'd like to learn about DOM and events, I recommend checking: http://domenlightenment.com/#11 (DOM Enlightenment book).

egbeago commented 3 years ago

This is better than react.com

Good insight

egbeago commented 3 years ago

Was checking to see if you have any write-up/on useReducer but I'm still checking, please if you have done any article on it please point me to it otherwise kindly write one. Thanks just came across this blog like yesterday and I'm a fan already

panzerdp commented 3 years ago

Was checking to see if you have any write-up/on useReducer but I'm still checking, please if you have done any article on it please point me to it otherwise kindly write one. Thanks just came across this blog like yesterday and I'm a fan already

Thanks @egbeago! Yes, I have plans to write an accessible post about useReducer().

Raheel-Saleem commented 3 years ago

Hey Man! your article on useEffect() is absolutely love ,easy to understand Thanks man but i have a question? lest assume i have a object named as data that is not a prop or any state variable can i still used in useEffect() callbacks and push into dependency array? for example...

export default UserData =()=>{ let data = {id:1, id:2, id:3} useEffect( ()=>{ console.log(data) } ,[ data ]) }

i would be very gratefull for you if you help and explain me in this scenario

ecatugy commented 3 years ago

Fantastic explanation, I passed your article to several developers in Brazil.

panzerdp commented 3 years ago

Fantastic explanation, I passed your article to several developers in Brazil.

Thanks @ecatugy!

svo-roni commented 3 years ago

Hello! Thanks for the explaination. I tried some of the stuff and i seem to get a different result. This should only trigged once, for i don't change the name, but it fires 2 times. Am i doing something wrong?

import React, {useEffect} from 'react';
import ReactDOM from 'react-dom';
import './index.css';

function Greet({ name }){

  const message = `Hello, ${name}!`;
  useEffect(() => {
    document.title = message;
    console.log("Triggered!");
  }, [name]);

  return(
    <div className="message">
      {message}
    </div>
  );

}
class App extends React.Component{
  render(){
    return (
          <div>
            <Greet name="Melissa" />
            <Greet name="Melissa" />
          </div>
    );
  }
}
panzerdp commented 3 years ago

Hello! Thanks for the explaination. I tried some of the stuff and i seem to get a different result. This should only trigged once, for i don't change the name, but it fires 2 times. Am i doing something wrong?

It triggers twice because you render 2 instances of the <Greet /> component.

// ....
class App extends React.Component{
  render(){
    return (
          <div>
            {/* Greet rendered twice */}
            <Greet name="Melissa" />
            <Greet name="Melissa" />
          </div>
    );
  }
}
svo-roni commented 3 years ago

Thanks for your fast response! But isn't that the example you gave at point 4? "4. The side-effect on component did update". How can i change the name without rendering another instance?

// First render
<Greet name="Eric" />   // Side-effect RUNS
// Second render, name prop changes
<Greet name="Stan" />   // Side-effect RUNS
// Third render, name prop doesn't change
<Greet name="Stan" />   // Side-effect DOES NOT RUN
// Fourth render, name prop changes
<Greet name="Butters"/> // Side-effect RUNS
panzerdp commented 3 years ago

Thanks for your fast response! But isn't that the example you gave at point 4? "4. The side-effect on component did update". How can i change the name without rendering another instance?

No, that's the same component, which re-renders with different props.

svo-roni commented 3 years ago

How can i achive the same? I don't see the difference^^

panzerdp commented 3 years ago

How can i achive the same? I don't see the difference^^

@svo-roni I updated the post and added demos to the examples you're asking. Now it should be easier to understand.

kanybekd commented 3 years ago

Hi Dima, your articles are awesome. Thanks. cheers

panzerdp commented 3 years ago

Hi Dima, your articles are awesome. Thanks. cheers

Thanks @kanybekd!

Kvntn commented 3 years ago

I tried to understand all componentDid/Will...() functions before getting started with useEffect(), but your tutorial opened my eyes ! I finally understand the uses of useEffect() and its cleanup function. I'll recommend this to React beginners ! Thank you !

panzerdp commented 3 years ago

I tried to understand all componentDid/Will...() functions before getting started with useEffect(), but your tutorial opened my eyes ! I finally understand the uses of useEffect() and its cleanup function. I'll recommend this to React beginners ! Thank you !

That's great @Kvntn! You're welcome.

redefinered commented 2 years ago

"How often the component renders isn't something you can control"

Am I reading this correctly? I'm a beginner and have a react experience of 5 years.

faiakak commented 2 years ago

Finally I discovered the diamond! Thanks for explaining better than any one else!

panzerdp commented 2 years ago

Finally I discovered the diamond! Thanks for explaining better than any one else!

You're welcome @faiakak!

shivjyotigarai commented 2 years ago

Amazing Tutorial.

I just have a small query in Component did update section. The code which you have provided here gives the following output in console.log()

This is an image

I only changed the App.js file slightly i.e I removed the timers and rendered the Greet component one after another as shown below.

import "./styles.css";
import { Fragment,useEffect, useState } from "react";
import { Greet } from "./Greet";

const NAMES = ["Eric", "Stan", "Stan", "Butters"];

export default function App() {

  return (
    <Fragment>
      <Greet name={NAMES[0]} />
      <Greet name={NAMES[1]} />
      <Greet name={NAMES[2]} />
      <Greet name={NAMES[3]} />
    </Fragment>
  );
}

Now the output is this

Any reason why the Side Effect statements are all executed at the same time. Like rendering the Greet component one by one and using a timer should not give any difference . Am I missing something ?

Thx

Sargnec commented 2 years ago

Hey Dmitri your guides always easy to understand. Thanks for these. I wanna ask something. In this tweet of Dan Abramov https://twitter.com/dan_abramov/status/1501735829332500482?s=20&t=JS79D_9po-Ytiz3FCiIg8Q He says we shouldnt use set state inside useEffect. How I'm gonna fetch my data and use it then. Am I understanding this correctly?