I had an awful experience at first with useEffect and its double call on React 18 while updating an app's dependencies. Now I get it. Helpful to avoid future bugs. Thank u!
I didn't try React 18 yet, but this video analysis served as the first move of upgrading. Thanks, a lot Jack, the way you explain helps me understand these concepts perfectly, I feel more confident and enjoy coding even more.
Maybe I'll give StrictMode another try. I ended up disabling it because of this side effect. Not because the code was buggy per say, but I just really didn't like seeing API calls fire twice in the network dev tools. Made it very confusing if I was specifically debugging the network call itself, plus it puts unneeded strain on the back-end. Since then I have begun to use react-query so perhaps I wouldn't notice if I re-enabled StrictMode.
It did trip me up because I forgot it's a thing. I was wondering why my API call was triggering twice on mount. Half an hour of debugging and I remembered that React 18 triggers double mount. Don't mind it at all, but it can be confusing. To be honest, it feels like React is getting more complicated in general. All quirks, re-rendering logic and other things can be hard to juggle in your head at the same time. Hopefully bunch of these manual steps we have to do these days will be resolved with React Forget and useEvent (in RFC at the moment) in the future. I'm working with React on a daily basis for over 3 years now and it can still trip me up and confuse me with useEffect, memoization and other things. Unfortunately, I don't have that much experience with any other frontend framework so I cannot say what is their complexity level compared to React.
I think the issue I have is that out of the box, react doesn't provide a state management system, sure, you could use react-query or redux, but you shouldn't be forced to. I've used useEffects for fetches and subscriptions. If those things are not meant to be done in a useEffect, then give documentation on how and where to do it and specific functions to do it instead of forcing people to use third party libraries.
This might be the best decision in the current scenario, but the fact it isn't immediately clear to everyone means it is still a poor developers experience regardless of the thought that went into it.
@@AndyPotts0 Seems like every release tries to fix a problem created in last release, and the fix for itself isn't even elegantly. Looks like React doesn't know where it is going. Can't see why people still insist on this lib.
@@ashuprakash6697 I think that Nuxt 3 is doing a great job considering learning speed, productivity and OOTB performance. Even if you like the syntax of React, SolidJs is also a good option. I also have to say that Angular fits well for very complex and hight scalable applications, but the learning curve is considerable.
This is a blessing! And I am, was now, also one of those who didn't get this double call, so just removed that stupid StrictMode. But I also am one of those who wanted to know if my cleanup really works but didn't know how to. So here it is, great!
Hello Jack, I think it's a mistake. Let me explain why. They activated this because of react 18 concurrent mode. And they are telling developpers that even on production this behaviour could happen, so they are now doing it on strict mode everytime so developpers are aware of it and don't spend hours understanding why they have sometimes this weird bug on production. So now in concurrent mode, components rendering is an interruptible process. meaning, component can be mounted, then finally unmounted because rendering was cancelled, then mounted again. This change, means that if you want to enable concurrent mode, and you used useEffect to fetch data, you will now need to change all your code (and this can be huge) to trigger fetching outside of useEffect or use third party libraries for fetching correctly (react-query is happily unnaffected because thanks to caching they already deduplicated concurrent calls). Like the migration guide tells us, this is BREAKING CHANGE. I would have hoped that with this breaking change they had introduced easy helpers, like a useUncancellable() or something for use cases where people don't want to use thirdparty store / event / fetching library. Now community has to handle it with mixed understanding of the problem and different solutions to something that was not an issue before.
Then what about API calls what is the right way of doing this?, people usually uses use effect to fetch data By the way, this comment makes a whole lot clearer what the issue is
@@pnx1990 me and my team have concluded that we'll now always use react-query for api calls. But like i said, there are tons of options as third party libraries: redux-toolkit, swr, recoiljs, zodios-react etc... The only thing i'll now not recommand is creating your own api call hook...
This doesn't feel like an actual reason. What's the point of upgrading if you wrap every error in a "use old behavior" hook? If they constantly have to aim for backwards compatibility they can never move forward.
React query solves this problem of useEffect being called twice in Strict mode due to caching. If cacheTime is set to zero, React query will also call the api twice.
How would you even go about moving API calls into a state manager like Zustand? Where would you put the fetch? Inside of the store.tsx? What even is a 'subscription'? A tcp connection? Sorry for the barrage of questions! P.S. Your videos are probably the best I've seen. The format and flow make everything easy to understand. Great teaching Jack
I'm a true believer that a "second generation" of React should be created, with a lot of cleanups. React is a beast that has got into monkey patching a lot of stuff.
That idea sounds acceptable on paper, but comes with some major downsides, not least of which is doubling development cost. This new React branch would require a bunch of community support, new features and redesign, but existing React would also still need community support, bugfixes documenting, etc. It's a huge cost investment, and who should bear that cost? There's still React 17 (and earlier) if you want a stable, LTS version that doesn't introduce new behaviours, which is sort of a 'second generation mini', if that makes sense.
@@bronzdragon fuckbook can afford it. Don't see why not. Vuejs is purely community driven and is light years ahead of react in every way possible except for the fact that people enjoy zucking dick.
I’m working in a new project, is legacy code and strict mode is out of the way 😢, the useEffect implementations are completely wrong in some places and there are some bugs 🐞 🐛 🐜 very hard to find and almost impossible to fix, definitely strict would be very helpful here, I’m moving to rtk and rtk query for the state management and I hope to someday clean all the side effect mess. No inference in Typescript and the abuse of generics it’s insane 😅 You might think I’m living a nightmare but actually I’m having fun doing the extreme makeup for this project and also I’m learning everyday, it turns into a nice personal challenge
I think that double mounting on useEffect is a good thing in developer mode. Especially in your Example Jack. Many developers who are learning React should learn that there are cases when you need to clean up your useEffects. It is and will be a best practice to do so. For me, it was something that I ignored when I started to learn React, and learned it the hard way.
Iirc they added it because in concurrent mode there are situations where the mount effect may actually be called twice. So they force it to happen in dev mode so you can catch it without depending on chance. It's there to protect the devs not to work against them
@@freddiemixell186 iirc, it is because native events can cause a new render to fire before the last render finished, and that causes React not to account for the side effect alredy being triggered. This is new in concurrent mode because in the non-concurrent (legacy) mode the render only yielded after the entire render was finished
@@smlgd This is however an edge-case, so misrepresenting it as the norm complicates performance and render optimization testing. It's ok for performance to take a bit
@@allpro2b Your component can also bail out of render with "Suspendable" component or hooks, that was concurrent mode is also about. And StrictMode is strict mode, you can use it or not. But it's here to do this kind of things.
Something that supposed to be called once, should not be allowed to be called twice. Why bend the rules of DX? Its like telling lightspeed to be a little bit faster than the max. I hate the new useEffect implementation since it introduces more confusion than improvements. I wont change my mind since it's a step back, and not forward. I don't want to code a workaround for that, but have to live with the side-effects... Development should be as close to Production as possible...... still, great video!
Where does it say it's supposed to be called once? It's called when a component mounts, but there's nothing saying a component can't be mounted multiple times though. It might happen for several reasons
@@smlgd An empty array dependency should only run once, as always referred to. I understand that multiple instances of an Component can be mounted, yet the useEffect will run once on mount. Doubling the amount is non-trivial. Why should it run twice in dev-environments but not in prod-environments? I can differentiate the environments via the `process.env.NODE_ENV` variable No need for the double call on useEffect.
Hey! Thanks for the video, it was helpful. I was going through different rabbit holes and was getting a bit mind boggling. I couldn't refer to the official React documentation lately and hence felt falling behind. Thanks for stressing the point to build the "idiomatic" react apps, that does re-emphasized the way I approach building them.
I don't want code libraries deliberately operating in an inconsistent manner as an way to train/babysit my developers. This will make rendering optimization and performance testing much, much more difficult and confusing. It would be better to allow specific debug flags for such things so devs/teams can opt-in, instead of requiring strict mode be completely disabled to avoid this one abnormal behavior.
Fascinating. The toughest pill for me to swallow is having code that behaves differently in development than in production. But if its a pill that saves me from production bugs then.... I'll take two.
Well that is it right there. This is generally a very bad practice. It’s the whole reason Docker exists to help guarantee what a developer authors in 1 environment works everywhere. But if you take a step back and just think about react in general from a beginners perspective or a seasoned dev trying to learn it coming from jQuery or Angular. Almost every language/technology I have ever used has some form of an “on load” event. And usually the naming is pretty obvious. With class components we had “didmount”. So we all had to adapt and learn that the equivalent to this is “useEffect” with an empty dependency array. For years countless blogs and tutorials have taught us all this is how you run code that should be run on first load and only first load. And now we have to factor in the double load during development just for react 18.
@@cas818028 Exactly! Hit the nail on the head. React isn't perfect but unfortunately we are stuck with it. Until something else gains popularity and is proven to work for large scale frontends.
This is EXACTLY the reason why the React team went ahead with this double effect decision - solving leaks of this nature is really difficult, they rather aggravate devs during development rather than figure out something is wrong in production.
@@cas818028 That's what you'd like to think, but try deploying a docker container to a lambda function - lambda runtime has its own rules (different linux user, writable only in root /tmp folder). long story short, even something like Docker DOESN'T work everywhere exactly the same. Very often (even in 2023) the magical words trope "works everywhere exactly the same" is still extremely hard to come by, if not impossible. In any case, this strictmode choice by the react team is barely a difference to production - all it is doing is guiding you to to write proper cleanup to your hooks - something everyone has until now neglected and assumed was not "totally" required, but actually, it should be.
I think in terms of DX retro compatibility if something could be called as this, should be good if you could choose if you want some new strict mode behavior like this or disable adding some disableDoubleEffect prop on this StrictMode comp. Thanks, nice video about this new "feat"
I think this situation is entirely avoidable if you have proper separation of concerns. useEffects should be used for managing the component state, not the business logic. Your API calls shouldn't depend on when a specific component mounts/unmounts, components are just pieces of UI. It just happened that components were usually mounted only once as your app/page loads, but that's no longer the case.
Well said. This is one of the biggest "mistakes" the react team made. The state and view are two separate concerns and life cycles. That said it is possible to separate them somewhat as the UI is just a function after all as well as the state. However, this adds more layers, abstractions and complexity to try "hide" a poor architectural design choice by react.
Could share a coding example for how would an API call would work not inside a useEffect? I am curious how would that work, showing loading, error state when not fetching inside a React component
@@anonymousBl1 check out react query. They abstract useEffect and useContext and a whole bunch of other react api methods. Its related to what I mentioned above.
@@mondo1926 i worked with react query, at the end of the day, they are using context and useEffect behind the scene and they have more logic around caching. At the end of the day it still lives in react world and there is still no separation of concerns. That is why i was curious about the comment above
@@anonymousBl1 " it is possible to separate them somewhat" is referring to something like react-query and how they specifically hide inner details of the react api. It does add another layer of complexity. However, has lots of other features. I wont get into that as its off topic. Maybe I wasn't clear enough in my original reply. Warts and all. React is one of the most used and popular libraries out there for UI's. I don't see it being replaced anytime soon (sign, its too complex for what it does). It is good to know its flaws though. Its just a tool in your tool belt. Knowing which tool to use for what job is important. In conlusion, it's not an easy task to completely separate the state from the UI. Unless you feel like creating yet another javascript framework (please dont!!). Svelte seems to be going in the right direction. Its much simpler and is gaining momentum.
I think they made the wrong call, even with all the context in this video. Pushing people towards libraries like Redux, just to have simple things like non-double-firing data fetching is dumb and adds complexity where it is not needed. I work somewhere where redux is OVERUSED for EVERYTHING. Over engineered to the max. Each keystroke changes the global state. You give people more rope (a complex state management system like redux) and they're going to hang themselves with it
You don't need to move to another library. Just run cleanup in your effects and add guards to avoid doubling up on network calls. Also, there are much simpler state management libraries like Zustand and Recoil, if you need global state management.
One problem still with this is that your fetch request will be fired twice, while the first one will be canceled if you implement a cancel mechanism. Therefore your dev tools network will be polluted by displaying twice the numer of requests.
you wont get this issue with react-query, it will check if the same request, and you can set interval of these requests. so stop doing fetch on useEffect
@@archmad react query its an extra library. you might not want to use that. Plus, something you might still want to useEffect. For instance, having a query {...} to fetch data everytime that changes. You'll have to "watch" that query in useEffect to fetch new data. Not sure if you can do that with react query
@@mrwho2513 you can create your own hook and provider that checks if data is new. this way you dont refetch same data multiple times. useSWR, or even redux can do these things. so not sure why you dont want to consider using a library. but it's up to you, but i suggest dont place it in useEffect, that's not really the place to go to for fetching, you will end up multiple fetches if you are not careful
@@archmad for project starting with 0 lines of react 18 code... that might be an idea. What do you do with projects with thousands of lines of code of old react, lower than v18?
I think if we call an API inside the useEffect and we are not handling the case where our API is calling and our component gets unmounted and the solution should be we have to stop the API calling using Abort Controller. But we sometimes forgot to add the Abort controller in the useEffect. So, this double mounting will help us in these cases where we have to add or handle these cases. Correct me if I am wrong Jack.
So in short: - Embrace the double console log since it is ON DEVELOPMENT MODE, and **StrictMode** works only on Dev Mode. There is nothing wrong with that, just get used until React Team figures out a clean solution. - so we move from useEffect to use a state manager, but it is up to us to decide the best implementation possible. There are many options to explore. So don't get scared :), it's ok.
@@ts8960 If I've understood Jack's explanation correctly, it's there to test that your component correctly cleans up after itself on unmount. It helps you to spot memory leaks and other issues, as Jack pointed out. The updated React docs are still in beta but definitely worth checking out.
@@sideshowlol alright thx Just to clarify i dont do anything about the double trigger its just there to make sure my useEffect works in that hypothetical scenario if it happens in production
@@ts8960 That's my understanding. It'll always do the mount-unmount-remount sequence when in Strict Mode. I suppose you could think of the first mount and unmount as the component test. You can always temporarily turn off Strict Mode to see if the behaviour of your component's useEffect is as expected and as it will be in production.
Jack, a question. It's clear for the interval and totally makes sense if you forget to properly clean-up things, but If let's say I have a react app with react-router, and on a certain page, I want to load some data on mount (once). If calling the function to get the data is not the correct place, then what should trigger that to fetch the data? Right now, I can imagine stopping the first network request if it's duplicated, or not calling the request if there is some data already in the store/state, but all of that still uses useEffect
Personally, I would use React-Query. The query client is a cache. And so react-query is going to manage that. That being said, if you want to do it on your own then use an AbortController.
I think once people start to understand why this behaviour happens it's a great idea. However as you mentioned the developer experience is not great and many people are left stumped to why it happens.
What would you suggest for handling a scenario where you have 4 sequential service calls and have to assess where to send the user to from the various response one might get? Right now I've opted for using react-query and three different useEffects each surveying the data and error objects from those queries, but been wracking my head thinking of a better way.
If four sequential calls are required I'd just bundle them into one function, like: async function updateUser(user) { await fetch(...); await fetch(...); await fetch(...); await fetch(...); } Same thing with getting data. React-Query doesn't care how many async requests are used to create the one fetch request for the RQ hook. It could be a single fetch, or a function that wraps mulitple fetchs and combines the results. Totally up to you.
Completly agree with your train of thought, however, I would not use the same name for the hook, why not use useEffectV2 ? I'm not comfortable with the idea of having two different behaviors using the same hook depending on the react version.
Thanks for the explanation. Honestly this whole strict mode looks like a React-specific hack, a workaround. What if I have API call on component mount, would it be executed twice? So previously I could avoid state manager for a simple project, but now I can't trust React to do this job anymore because it creates unnecessary API calls
This is only in development mode. In production it would still behave the same, this is just a tool to highlight poorly written and potentially problematic react code
In concurrent mode your component can be mounted twice, yes, so you may have double API calls. It's just that it's chance-based, and strict mode helps you by making you not depend on that to see the errors occuring.
True, it triggers a double call and now it is your job to “not” update the state on an unmounted component and cancel or abort the request. I do console log request xxxx canceled and only here I know I have cleaned up my component very well on unmount.
This is the biggest thing for me, without using a 3rd party library like React Query, what do they recommend for data fetching now? Typically people would fetch data in a `useEffect` but now under strict mode it fires the API call twice and updates state twice which seems unnecessary and a bit annoying. Sure we can probably create a custom solution to de-duplicate requests ourselves but it seems annoying that this very common flow is not already built-in. I get that strict mode is trying to show developers that this race condition may exist where your `useEffect` may execute more than once concurrently so you need to clean things up but I feel like this was already obvious...
I'm not convinced. It seems to run twice only for a useEffect hook without dependencies and in only under strict mode in development. I want my development code to run close to my production code, not introduce side-effect that will never occur in production. I get what they're trying to do but it seems like they're introducing quite inconsistent behaviour to solve something which essentially amounts to developer sloppiness. edit: Jack, if you're reading this I just discovered your channel and your content is great!
Ideally, if you use the useEffect correctly, you wouldn't really need to worry about it executed twice, only if you are handling the cleanup function properly. Often times people who are facing this issue are mostly because of they are trying to do something when a component "on mount", but here's the thing, useEffect was never meant for replacing the component lifecycle from class component. So if you try to write the useEffect with lifecycle thinking model, you will find yourself facing this issue a lot.
Every other library using the useeffect how it isn't supposed to be used has to be updated and Backward compatibility is broken for those 3rd party libraries.
I think I've misunderstood something, but how will global state libraries ensure the code runs only once? Do we move useEffect code to global store level? Awesome video btw! I was also confused by this decision from React JS maintainers.
I was never really convinced to replace the class based components with hooks. And I now also see why I am not gonna do it. If it works, don't try to fix it...
i currently learning suspense on react 18, mr jack can you explain to us the best practice to use suspense? especially nested componets, i have problem with those, my code working but i don't think it's right 😅, btw i think its my first time to comment on your channel, ijust want to say thank you i learn a alot of things from your tutorial
In the 6:24 (NOT FIX) section, you mentioned that the place to make API calls would no longer be useEffect but state management libraries, I am having trouble finding documentation to achieve this with any state library and would greatly appreciate it if you could redirect me to any piece of information where I can get the knowledge on how to do that
Non programming related question - how did you add yourself as an overlay on top of the video? Looks very pleasing and without distractions and blends well.
@@noorkhorasi That's a green screen. My background is my actual office, but I shoot against a green screen and then replace that with a plate, and later with code so that I can do all kinds of fun video effects. I use Adobe products (Premiere and After Effects). They have a green screen keyer built in but I use a third party plugin that I like which I think produces better results. Honestly, most video editing software has chroma key removal feature, I think including OBS if you want to go full free.
hey Jack can you please share your VS code exenions list. and configuion for the terminal and also your theme as well. that auto-complete looks very cool but could not able to find it anywhere.
Thanks Jack! I like the notion of "Maybe just don't put it in the useEffect()". I seem to remember that there is some reason that one declares fetch() functions within the useEffect and not outside of it - Honestly don't quite remember why, but if you know, would that also apply to something like a subscription() function?
I tried every kinds of hacks too. FInally, after this video I understand why. Thank you, but the point remains... There could be a console warning in the dev mode, explaining the same. :/
Hey @jack What about the component unmount event. There are possibilities where you need to remove some data from the global state on component unmount event. The same data is actually being used in the current component as well.
The unmount event is modeled in the cleanup function of the useEffect. The component is mounted, unmounted, and mounted again, in series, not in parallel. The first mounted component will not exist at the same time as the component that is mounted the second time around. So you should just make sure that whatever you put in global state is... removed, or updated, or whatever you want, in the cleanup function.
I'm angular developer programming in React 18 this is a bug and they need to fix that, Angular don't do that and I don't like that React team just put this under the rug make it's very hard to explain to team when we already know the answer. Great Video
Can you make a video for developers who are reaching 40 or more age can they stay in programming or they will be forced to do retirement after certain age
I certainly hope I don't get forced into retirement. :) I have been thinking about a video about habits to form for a long career in coding, but it wouldn't be anything related to age. IMHO you can be very early in your career and fall into a short-sighted mindset where it would be hard to get hired.
This is an issue with our industry. Some shops have become less sexist/misogynist (not all). Nearly all shops are ageist. I just (2022) turned 70. My programming chops are not the issue -- I've heard no complaints about my code/coding style. Shops use various euphemisms -- "too senior", "too experienced for this role" -- and they all amount to the same thing. Most 30-something managers that I encounter are profoundly uncomfortable with candidates who -- in my case -- invented the technologies the managers are asking about on an interview check-list. I was part of the small cabal that created "Extreme Programming" (today we call it "Agile") -- I've been doing test-driven code since before many of today's hiring managers were born. I think the resulting "experience imbalance" is too difficult for hiring managers to embrace. For me, there was a distinct "knee" in the curve at around 60. During my 40s, hiring managers and recruiters eagerly pursued me and it never took more than a few days to get multiple offers to choose from. That changed gradually during my 50s, and I hit a brick wall at 60 -- I was very fortunate to be hired into a role that lasted 5 years. One comment, though -- if it is at all possible, don't let yourself be "forced to do retirement". I strongly encourage folks to do whatever they must to live sustainably without external salary -- social security, 401Ks, etc. The technical landscape today offers a myriad of marvelous alternatives for pretty much every technical choice -- nearly all very affordable. I don't self-describe as "retired". Instead, I work on what I want at the pace I want and with quality standards that I choose. I am mercifully and finally free of all those corporate meetings, "strategy presentations", HR reviews, and so on and so forth that always burn at least half of the usual work-day clock-time. On any given day today, I write better code and have more fun doing it than I did during my last two years at a major corporation (Experian). When I choose to embrace React and NodeJS, I don't have to do battle with "corporate standards" and "IT support" to gain their permission to introduce "new" technology to a corporate infrastructure. I do occasionally have to deep-dive into issues with the support team of particular providers and that's approximately the same activity that I used to have to do with corporate IT support -- except the vendor support teams are generally more competent (with some notable exceptions). I don't EVER again have to deal with rotating Microsoft Exchange and Microsoft Sharepoint credentials. My bottom line is that I encourage you to do whatever you are able to secure a sustainable lifestyle without a traditional employer by the time you hit 70. During that time, learn how to manage yourself. Learn what you love and what you hate on a day-to-day basis. Then celebrate your freedom on the day your social security benefits kick in. For me, it has felt more like graduating from school than anything else. I am finally free -- utterly free -- of ridiculous and frustrating corporate "stuff". I finally have a rigorous but usually fair manager (myself). Best of all, I look forward to spending pretty much every day doing what I enjoy most in life -- coding.
I always thought the double call was a non avoidable requirement because if the nature of the useEffect. Once the component mounts, it fires. The data may not be available yet, and if it's a argument, it fires again. That was always my thought process.
In production an empty dependency array fires only once. If it has dependency values then it fires once on startup and again whenever the values change.
Does it mean that in the production useEffect does clean up automatically? Because in the bad watch still the setinterval exist from the previous run and did not clean up
No, there is never anything automatic like that in React. If you create an interval in your effect you need to provide a cleanup function. 100% that is on you. React has no idea about what you are doing in your useEffect.
@@jherr Thanks Jack but I am confused as you mentioned in the video that in the production the StrictMode automatically is removed and based on the video (4 min:26 sec) that you showed if you remove the StrictMode the BardStopWatch and the GoodStopWatch works the same (clear the intervals in unmount mode happens automatically?)
@@sam-zy2dn Again, never any automatic in React. React does NOT know that you have created an interval in your useEffect. The reason they are the same in this case is that the stopwatches are not unmounted after they are mounted. If there was a control that flipped their visibility, that would force an unmount and the Good Stopwatch would be cleaned up properly, and the Bad Stopwatch would leak. Feel free to demonstrate this you yourself by adding a non-CSS based toggle. You'll be able to see that the Bad stopwatch continues to fire after the component has been unmounted, because React will not clear any intervals you have set.
My perhaps awful habit is to write React code based on my current understanding of approaches that work best, then rely on the several EsLint spankings to guide me towards when and where to use "useEffect" and its friend "useCallback". I love Jack's videos because they help me better understand what's actually happening as I step through things in my VSC debugger. I do find myself pulling handlers into the top of a "useEffect" block rather than sorting out the dependency graph that results from leaving them at the top level of the component. At this very moment I'm trying to sort out "click", "blur", and "focusout" event handling so that I dismiss a pane if the user clicks anywhere outside it -- and still catch clicks from components inside the pane (be careful about "blur"!). It seems easiest to add and remove event listeners in the "useEffect" block and provide local (to the "useEffect" block) handlers for those added events. I mention this because it exemplifies the way I use "useEffect". I think my code will be unaffected by the double-pump (assuming that React is able to avoid adding and removing event listeners multiple times). I don't mind the extra calls. I'm still not totally sure if this "double-pump" was added by design or if it is a perhaps unintended consequence of some other choice made elsewhere in React. So long as things keep working, I don't care.
@@jherr : Cool! Just a technical nit -- when you set breakpoints inside a useEffect block (in VSC), are those breakpoints now triggered twice? You briefly observed that some of the context (ref's, for example) might be different on the second pass. Is there specific guidance about when the second pass occurs and what might be different?
@@thomasstambaugh5181 I wouldn't spend any time thinking about first or second pass. If you are doing that then you are trying to work around this. You should write your useEffects so that run once, twice, or a thousand times shouldn't matter, they should setup and cleanup without leaks every time.
@@jherr I get that, and I'm not trying to work around it (I'm still on React 17 in fact). When I upgrade to v18 and I'm debugging a useEffect block, then I'll see each hit on a breakpoint inside the useEffect block. I'm just wondering what I can expect when I upgrade to v18.
Sorry but this is completely unacceptable. We are talking about lifecycle "hooks" which worked for almost 10 years without anyone being confused. React gives us components, then React is responsible to properly handle the lifecycle. Why is it acceptable for us to install third party libraries just to ensure we are only fetching a list once? This is just wrong.
It only happens, if you run strict mode, locally. The idea behind it is to help people catch issues with useEffects not cleaning up. If you don't need this feature, and want it to fire once in dev, jus remove strict mode?
@@mehdiwadoud8098 If I understood right, the strict mode will be the only mode in future react versions. You still have the chance to disable it, but not in the future versions
What about components that do API calls in useEffect and those API calls are not idempotent? Like for example a get route that also logs everytime someone requests info. It would be logging twice, wouldn't it?
I wrote a whole article about this since people are having issues with it: javascript.plainenglish.io/react-18-useeffect-double-call-for-apis-emergency-fix-724b7ee6a646 Basically there is no native "fix" in React. The `useEffectOnce` "fix" that is out there doesn't work. The best thing to do is to use something like react-query or swr which manage queries and caching outside of the context of React and therefore are immune to this "issue".
Just need a Mantine alternative or better in Vue and I may never be around react again. Been investing more and more in Vue and Nuxt 3. But nothing is perfect.
I don't think that the double effect call should be an issue. But what I don't agree with is that moving the logic to the state solves the heavyweight issue. The component that calls the heavy weight action, will still call it inside an `useEffect`, this is of course if it's not moved inside the state initialization (which will add that heavyweight thing regardless if it's needed), or prevent the cleanup of the state (which will leave that heavyweight state uncleaned). So either way, you still cannot properly avoid the heavyweight functionality being called twice inside the `useEffect`. Edit: What I find more irritating about React 18 strict mode, is that you have to upgrade to the latest version of react-router (v6), as the previous version will not work anymore. And it has a nasty issue, that it will re-render any components that uses `useNavigate` whenever the route changes, and the issue was opened from 2020, and was not fixed so far (and it doesn't seem to be the case in the near future).
In my current product I have a bunch of subscriptions that are established outside of the React context altogether at application startup time. Those subscriptions then pump data into the UI through Zustand, which has support for setting state both inside and outside of the React context.
Just disable strict mode. If the design of useEffect, is so that you can call a bunch of actions multiple times and they can be cleaned up - and you want something only called once, and want to run strict mode - you are being encouraged architecturally to move those actions outside of the react component lifecycle, into something like a state management library, and have your components simply 'react' to state changes.
@@thorbjornbrancher5883 where should you move the initialization action for reading the data from the api, data that is needed only in a component? Again, I don't see an issue regarding being called twice, what I'm saying is that it's not always a solution to move the things outside the effect. You should move it if it makes sense, not just to get around the double effect.
@@ionut-cristianratoi7692 In your specific use case I would 100% disable strict mode. Then I would try and further understand how to architect your specific setup. I personally use nextJS, so I would take advantage of their i18n config in this case.
@@thorbjornbrancher5883 I understand that NextJS solves that with the page hydration mechanism, but this shouldn't be a requirement for this kind of architecture. Regarding the disabling of strict mode, for the example with a heavyweight API call, probably there's no other way, than to just disable it. But if it's just a standard API call, I would just leave strict mode on, and cancel the request on cleanup. And each time the component is run in dev-mode, it will always cancel the first request. As the benefit of strict-mode with out-weight the downsides of the dev-mode.
Wait, if the comp remounts doesn’t it get a separate setCount function? I get the first interval leaking but aren’t the two intervals controlling separate states? Why is the counter updating twice as fast?
Hi Jack, If I use redux with thunk would I not have to dispatch my asyn api related actions inside the useEffect? Would I not still have the same 2 call issue using state management? Thanks for video I’ve been struggling with this myself
I wasn't sold before but I am now. The only problem is that there are still wildly popular libraries (like react-beautiful-dnd) that are in sort of maintenance mode, and are broken when this is applied. It's super annoying...
I just turned off strict mode because they was way to confusing to me when debugging... Than again I was just starting out with react, and I'm not even sure what other benefits does strict mode have.
I started using React after 18 was already out, my website loads a KJV bible, once is enough, but loading it twice was a big headache for me. I resorted to this, using useRef. Now I should learn to clean up. And I'm glad it's only in dev mode. useEffect(() => { if(!effectRan.current) { getPosts().then(json => { setPosts(json.books) }) } return () => effectRan.current = true }, [])
Scenario: I have 2 components, 1st component has a dropzone where you can keep dropping files and it renders a list of those files using 2nd component which starts the upload onmount and shows the progress. How would I make sure that it doesn't upload it twice?
I'm not concvinced. Like "you cant do stuff you used to within the platform, but come on you have state managers". So you're making your framework less useful, less convenient, more confusing and unpredictable. And I don't get, what's the goal? Flaging few depreciated uses that few used You said you were convinced. How? They said to think of useEffect as synchronisation, but it's less useful this way for requests, as you won't want to wait twice
It is still not clear to me where should I put my external API calls. In my scenario, I need to grab some data from my web service, usually, I do that inside my useEffect, there is nothing to be cleared here. Where it should goes?
They should have waited to complete render-as-you-fetch before tightening the grip on strict mode. Data hydration is the big painpoint for me with this feature, because I use render-then-fetch (as I’m sure most do). Sure, it forces me to use interceptors on my api calls, which I _guess_ is good…. Even in dev, I’m querying for user data from my cloud database, which happens twice on every page load now, even if I cancel the request in my cleanup function. Idk, I guess I’m still not sold. I’ve already been using cleanups for web api subscriptions, etc. so this doesn’t clear it up for me :/
It looks like YT deleted my comment due to a link but have a look at issue 24553 in React repo to see perspective of complex component maintainer (AG Grid is no toy)
To me it feels like the React team finally understood the fact that useEffect itself is hard to understand and use correctly by devs. It's not intuitive, there's too much implicity in it about what happens and how you should use it. The explicitly named lifecycle methods that we had before were easier to understand. The double calling useEffects feels like a desperate move to fix something that is broken by its core. It feels like a hack on top of something that is not working good in the first place. I see it will create many problems: 1. Performance; duplicate api calls, duplicate unnecessary renderings of components 2. Weird component flashes; components rendering twice can cause lot of visual bugs and weirdness 3. Strict mode will increase the gap between development mode and production mode. This is bad. You always want your development mode to be as similar as possible to production mode. The larger the gap, the worse. Since now you do no longer test your production code anywhere except in production. You want the code to work in dev mode exactly as it works in production to catch bugs. 4. The whole concept of 'we force you to render your components twice to teach you how to use our useEffect correctly' has something thoroughly wrong about it. If you have to go such measures, doesn't that imply that there's something too complicated about the useEffect in the first place?
I'm left a little confused as to what the moral of the story is here. I understand the point that there are cases where you need to clean things up in your useEffect but most of the times you don't need to do any cleanup. Making calls to an API is one of the most common use cases of useEffect and you don't need to worry about removing a setTimeOut or anything like that. Can we still useEffect and have confidence that it will only run once without strictmode?
Yes. You can. useEffect with an empty dependency array is run once on mount. In strict mode each component is mounted twice. In non-strict mode components are mounted just once, so the useEffect will get run just once.
That's OK to use a state management instead of the useEffect. One question though, how the Redux possibly knows that your component is mounted and run the heavy process once on that mount, if there are no lifecycle hooks available for that and they run twice when intended run once? That's really another stick in a wheel, honestly .
I'm not sure why redux would "know your component is mounted". You'd have to send the store you construct and action from a useEffect that you construct and then respond to it. And you could structure the logic of how you respond to it any way you choose. Your store keep track of whether or not you have the heavyweight process in flight and then ignore subsequent requests to start it.
@Jack Herrington As far as I understood the problem is that the useEffect fires twice. If you send action via useEffect, it doesn't resolve the problem, it still fires twice. If you suggest that logic of the store should track , eliminate or debounce the possible double fires, you are on a wrong way. The point of the external state management is decoupling the logic and the UI layer, the store shouldn't resolve the problems of the useEffect timing. Honestly I don't see a right solution here.
@@golden_smiles I don't see how a state manager knowing that it has a process in flight and ignoring subsequent requests to start a process is "going the wrong way".
i dont understand. how does one set state then? would have been nice if you showed an example. not just saying redux, we are using redux and i dont know how to set state after calling endpoint only once, if not for a convoluted amounts of if statements. what am i missing here?
I'm not convinced at all about the double call of useEffect, seems very weird like devs were blowing each other minds when discussing pros and cons :) ... I like simplicity and not behaviour that doesn't make sense.
It is unusual that a library would have a "stress test" tool like this baked into it. On the plus side we can opt into and out of it. I do hope the React folks are reading the comments in here.
It's really important to understand that a component function getting run is NOT equivalent to a DOM re-render. React is a VDOM framework. So when a component is run it generates virtual DOM elements that are then compared to the real DOM and only when there is a difference is the DOM updated. So a component can be run thousands of time and never for a DOM re-render unless the props or state change.
@@jherr It still runs unnecessary javascript comparisons that would not be needed. Also, there are cases where the dom would be different. For example if you want to show precise timing, or if your useEffect generates new values (by randomisation or by count).
10 minutes of accurate explanation. Pure gold. Thank you Mr. Herrington!
I had an awful experience at first with useEffect and its double call on React 18 while updating an app's dependencies. Now I get it. Helpful to avoid future bugs. Thank u!
I didn't try React 18 yet, but this video analysis served as the first move of upgrading. Thanks, a lot Jack, the way you explain helps me understand these concepts perfectly, I feel more confident and enjoy coding even more.
Maybe I'll give StrictMode another try. I ended up disabling it because of this side effect. Not because the code was buggy per say, but I just really didn't like seeing API calls fire twice in the network dev tools. Made it very confusing if I was specifically debugging the network call itself, plus it puts unneeded strain on the back-end.
Since then I have begun to use react-query so perhaps I wouldn't notice if I re-enabled StrictMode.
I love you, spent all day trying to work out why one of my components was getting double called with a similar set interval function.
It did trip me up because I forgot it's a thing. I was wondering why my API call was triggering twice on mount. Half an hour of debugging and I remembered that React 18 triggers double mount. Don't mind it at all, but it can be confusing.
To be honest, it feels like React is getting more complicated in general. All quirks, re-rendering logic and other things can be hard to juggle in your head at the same time. Hopefully bunch of these manual steps we have to do these days will be resolved with React Forget and useEvent (in RFC at the moment) in the future. I'm working with React on a daily basis for over 3 years now and it can still trip me up and confuse me with useEffect, memoization and other things. Unfortunately, I don't have that much experience with any other frontend framework so I cannot say what is their complexity level compared to React.
I think the issue I have is that out of the box, react doesn't provide a state management system, sure, you could use react-query or redux, but you shouldn't be forced to. I've used useEffects for fetches and subscriptions. If those things are not meant to be done in a useEffect, then give documentation on how and where to do it and specific functions to do it instead of forcing people to use third party libraries.
This might be the best decision in the current scenario, but the fact it isn't immediately clear to everyone means it is still a poor developers experience regardless of the thought that went into it.
React dev experience is trash
@@AndyPotts0 As a longtime useEffect PTSD victim I agree with Andy here
@@AndyPotts0 Seems like every release tries to fix a problem created in last release, and the fix for itself isn't even elegantly. Looks like React doesn't know where it is going. Can't see why people still insist on this lib.
@@HenriqueRotava which framework do you recommend then?
@@ashuprakash6697 I think that Nuxt 3 is doing a great job considering learning speed, productivity and OOTB performance. Even if you like the syntax of React, SolidJs is also a good option. I also have to say that Angular fits well for very complex and hight scalable applications, but the learning curve is considerable.
Thanks!
I'm watching it again and I wish I could double like it!
Thanks a lot, Jack!
This is a blessing! And I am, was now, also one of those who didn't get this double call, so just removed that stupid StrictMode. But I also am one of those who wanted to know if my cleanup really works but didn't know how to. So here it is, great!
Hey dear how are you doin?
Hello Jack,
I think it's a mistake. Let me explain why.
They activated this because of react 18 concurrent mode. And they are telling developpers that even on production this behaviour could happen, so they are now doing it on strict mode everytime so developpers are aware of it and don't spend hours understanding why they have sometimes this weird bug on production.
So now in concurrent mode, components rendering is an interruptible process. meaning, component can be mounted, then finally unmounted because rendering was cancelled, then mounted again.
This change, means that if you want to enable concurrent mode, and you used useEffect to fetch data, you will now need to change all your code (and this can be huge) to trigger fetching outside of useEffect or use third party libraries for fetching correctly (react-query is happily unnaffected because thanks to caching they already deduplicated concurrent calls).
Like the migration guide tells us, this is BREAKING CHANGE.
I would have hoped that with this breaking change they had introduced easy helpers, like a useUncancellable() or something for use cases where people don't want to use thirdparty store / event / fetching library.
Now community has to handle it with mixed understanding of the problem and different solutions to something that was not an issue before.
Insightful 🙏
Then what about API calls what is the right way of doing this?, people usually uses use effect to fetch data
By the way, this comment makes a whole lot clearer what the issue is
@@pnx1990 me and my team have concluded that we'll now always use react-query for api calls.
But like i said, there are tons of options as third party libraries: redux-toolkit, swr, recoiljs, zodios-react etc...
The only thing i'll now not recommand is creating your own api call hook...
This doesn't feel like an actual reason. What's the point of upgrading if you wrap every error in a "use old behavior" hook?
If they constantly have to aim for backwards compatibility they can never move forward.
React query solves this problem of useEffect being called twice in Strict mode due to caching. If cacheTime is set to zero, React query will also call the api twice.
How would you even go about moving API calls into a state manager like Zustand? Where would you put the fetch? Inside of the store.tsx? What even is a 'subscription'? A tcp connection?
Sorry for the barrage of questions!
P.S. Your videos are probably the best I've seen. The format and flow make everything easy to understand. Great teaching Jack
I'm watching your channel for the first time. I really liked it. Keep making content! Greetings from Russia with best wishes.
I'm a true believer that a "second generation" of React should be created, with a lot of cleanups. React is a beast that has got into monkey patching a lot of stuff.
That idea sounds acceptable on paper, but comes with some major downsides, not least of which is doubling development cost. This new React branch would require a bunch of community support, new features and redesign, but existing React would also still need community support, bugfixes documenting, etc. It's a huge cost investment, and who should bear that cost?
There's still React 17 (and earlier) if you want a stable, LTS version that doesn't introduce new behaviours, which is sort of a 'second generation mini', if that makes sense.
@@bronzdragon well Preact kinda did it and the guy isn't a billionaire, so...
isn't SolidJS that (React second generation)?
@@bronzdragon fuckbook can afford it. Don't see why not.
Vuejs is purely community driven and is light years ahead of react in every way possible except for the fact that people enjoy zucking dick.
SolidJS is pretty much 2nd generation React. They use JSX and React concepts, but it's more performant and the API is a lot nicer.
I’m working in a new project, is legacy code and strict mode is out of the way 😢, the useEffect implementations are completely wrong in some places and there are some bugs 🐞 🐛 🐜 very hard to find and almost impossible to fix, definitely strict would be very helpful here, I’m moving to rtk and rtk query for the state management and I hope to someday clean all the side effect mess.
No inference in Typescript and the abuse of generics it’s insane 😅
You might think I’m living a nightmare but actually I’m having fun doing the extreme makeup for this project and also I’m learning everyday, it turns into a nice personal challenge
I think that double mounting on useEffect is a good thing in developer mode. Especially in your Example Jack. Many developers who are learning React should learn that there are cases when you need to clean up your useEffects. It is and will be a best practice to do so. For me, it was something that I ignored when I started to learn React, and learned it the hard way.
Iirc they added it because in concurrent mode there are situations where the mount effect may actually be called twice. So they force it to happen in dev mode so you can catch it without depending on chance. It's there to protect the devs not to work against them
@@smlgd why would that happen in concurrent mode? Is it going to call useEffect again when network conditions improve or something?
@@freddiemixell186 iirc, it is because native events can cause a new render to fire before the last render finished, and that causes React not to account for the side effect alredy being triggered. This is new in concurrent mode because in the non-concurrent (legacy) mode the render only yielded after the entire render was finished
@@smlgd This is however an edge-case, so misrepresenting it as the norm complicates performance and render optimization testing. It's ok for performance to take a bit
@@allpro2b Your component can also bail out of render with "Suspendable" component or hooks, that was concurrent mode is also about. And StrictMode is strict mode, you can use it or not. But it's here to do this kind of things.
Something that supposed to be called once, should not be allowed to be called twice. Why bend the rules of DX? Its like telling lightspeed to be a little bit faster than the max. I hate the new useEffect implementation since it introduces more confusion than improvements. I wont change my mind since it's a step back, and not forward. I don't want to code a workaround for that, but have to live with the side-effects... Development should be as close to Production as possible......
still, great video!
Where does it say it's supposed to be called once? It's called when a component mounts, but there's nothing saying a component can't be mounted multiple times though. It might happen for several reasons
@@smlgd An empty array dependency should only run once, as always referred to. I understand that multiple instances of an Component can be mounted, yet the useEffect will run once on mount. Doubling the amount is non-trivial. Why should it run twice in dev-environments but not in prod-environments? I can differentiate the environments via the `process.env.NODE_ENV` variable No need for the double call on useEffect.
Hey! Thanks for the video, it was helpful. I was going through different rabbit holes and was getting a bit mind boggling. I couldn't refer to the official React documentation lately and hence felt falling behind. Thanks for stressing the point to build the "idiomatic" react apps, that does re-emphasized the way I approach building them.
I don't want code libraries deliberately operating in an inconsistent manner as an way to train/babysit my developers. This will make rendering optimization and performance testing much, much more difficult and confusing. It would be better to allow specific debug flags for such things so devs/teams can opt-in, instead of requiring strict mode be completely disabled to avoid this one abnormal behavior.
I think SolidJS is looking better and better.
I never turn it on as its so confusing and I haven't find a scenario it can help rather than disturb
Fascinating. The toughest pill for me to swallow is having code that behaves differently in development than in production. But if its a pill that saves me from production bugs then.... I'll take two.
Well that is it right there. This is generally a very bad practice. It’s the whole reason Docker exists to help guarantee what a developer authors in 1 environment works everywhere.
But if you take a step back and just think about react in general from a beginners perspective or a seasoned dev trying to learn it coming from jQuery or Angular. Almost every language/technology I have ever used has some form of an “on load” event. And usually the naming is pretty obvious. With class components we had “didmount”. So we all had to adapt and learn that the equivalent to this is “useEffect” with an empty dependency array. For years countless blogs and tutorials have taught us all this is how you run code that should be run on first load and only first load. And now we have to factor in the double load during development just for react 18.
@@cas818028 Exactly! Hit the nail on the head. React isn't perfect but unfortunately we are stuck with it. Until something else gains popularity and is proven to work for large scale frontends.
Spoken like a boss who never had a sync bug in production...
This is EXACTLY the reason why the React team went ahead with this double effect decision - solving leaks of this nature is really difficult, they rather aggravate devs during development rather than figure out something is wrong in production.
@@cas818028 That's what you'd like to think, but try deploying a docker container to a lambda function - lambda runtime has its own rules (different linux user, writable only in root /tmp folder). long story short, even something like Docker DOESN'T work everywhere exactly the same. Very often (even in 2023) the magical words trope "works everywhere exactly the same" is still extremely hard to come by, if not impossible. In any case, this strictmode choice by the react team is barely a difference to production - all it is doing is guiding you to to write proper cleanup to your hooks - something everyone has until now neglected and assumed was not "totally" required, but actually, it should be.
I think in terms of DX retro compatibility if something could be called as this, should be good if you could choose if you want some new strict mode behavior like this or disable adding some disableDoubleEffect prop on this StrictMode comp. Thanks, nice video about this new "feat"
helped a lot, thanks! I just upgraded to 18 and I was confused what the heck is happening with my app :D now I know.
waow thank you so much . You have a natural talent for explaining things well.
I think the double mounting is good practice because it's detected the leak problems and the refs issues your correct on that
I think this situation is entirely avoidable if you have proper separation of concerns. useEffects should be used for managing the component state, not the business logic. Your API calls shouldn't depend on when a specific component mounts/unmounts, components are just pieces of UI. It just happened that components were usually mounted only once as your app/page loads, but that's no longer the case.
Well said. This is one of the biggest "mistakes" the react team made. The state and view are two separate concerns and life cycles. That said it is possible to separate them somewhat as the UI is just a function after all as well as the state. However, this adds more layers, abstractions and complexity to try "hide" a poor architectural design choice by react.
Could share a coding example for how would an API call would work not inside a useEffect? I am curious how would that work, showing loading, error state when not fetching inside a React component
@@anonymousBl1 check out react query. They abstract useEffect and useContext and a whole bunch of other react api methods. Its related to what I mentioned above.
@@mondo1926 i worked with react query, at the end of the day, they are using context and useEffect behind the scene and they have more logic around caching. At the end of the day it still lives in react world and there is still no separation of concerns. That is why i was curious about the comment above
@@anonymousBl1 " it is possible to separate them somewhat" is referring to something like react-query and how they specifically hide inner details of the react api. It does add another layer of complexity. However, has lots of other features. I wont get into that as its off topic. Maybe I wasn't clear enough in my original reply.
Warts and all. React is one of the most used and popular libraries out there for UI's. I don't see it being replaced anytime soon (sign, its too complex for what it does). It is good to know its flaws though. Its just a tool in your tool belt. Knowing which tool to use for what job is important.
In conlusion, it's not an easy task to completely separate the state from the UI. Unless you feel like creating yet another javascript framework (please dont!!). Svelte seems to be going in the right direction. Its much simpler and is gaining momentum.
I think they made the wrong call, even with all the context in this video. Pushing people towards libraries like Redux, just to have simple things like non-double-firing data fetching is dumb and adds complexity where it is not needed. I work somewhere where redux is OVERUSED for EVERYTHING. Over engineered to the max. Each keystroke changes the global state. You give people more rope (a complex state management system like redux) and they're going to hang themselves with it
run
You don't need to move to another library. Just run cleanup in your effects and add guards to avoid doubling up on network calls.
Also, there are much simpler state management libraries like Zustand and Recoil, if you need global state management.
One problem still with this is that your fetch request will be fired twice, while the first one will be canceled if you implement a cancel mechanism. Therefore your dev tools network will be polluted by displaying twice the numer of requests.
you wont get this issue with react-query, it will check if the same request, and you can set interval of these requests. so stop doing fetch on useEffect
@@archmad react query its an extra library. you might not want to use that. Plus, something you might still want to useEffect. For instance, having a query {...} to fetch data everytime that changes. You'll have to "watch" that query in useEffect to fetch new data. Not sure if you can do that with react query
@@mrwho2513 you can create your own hook and provider that checks if data is new. this way you dont refetch same data multiple times. useSWR, or even redux can do these things. so not sure why you dont want to consider using a library. but it's up to you, but i suggest dont place it in useEffect, that's not really the place to go to for fetching, you will end up multiple fetches if you are not careful
@@archmad for project starting with 0 lines of react 18 code... that might be an idea. What do you do with projects with thousands of lines of code of old react, lower than v18?
@@mrwho2513 you are asking the wrong person
I think if we call an API inside the useEffect and we are not handling the case where our API is calling and our component gets unmounted and the solution should be we have to stop the API calling using Abort Controller. But we sometimes forgot to add the Abort controller in the useEffect. So, this double mounting will help us in these cases where we have to add or handle these cases. Correct me if I am wrong Jack.
Yep, this will help smoke out issues of not properly using the abort controller.
So in short:
- Embrace the double console log since it is ON DEVELOPMENT MODE, and **StrictMode** works only on Dev Mode. There is nothing wrong with that, just get used until React Team figures out a clean solution.
- so we move from useEffect to use a state manager, but it is up to us to decide the best implementation possible. There are many options to explore.
So don't get scared :), it's ok.
am i not supposed to do something to prevent the double effect? isnt that the point of it
@@ts8960 If I've understood Jack's explanation correctly, it's there to test that your component correctly cleans up after itself on unmount. It helps you to spot memory leaks and other issues, as Jack pointed out. The updated React docs are still in beta but definitely worth checking out.
@@sideshowlol alright thx
Just to clarify i dont do anything about the double trigger its just there to make sure my useEffect works in that hypothetical scenario if it happens in production
@@ts8960 That's my understanding. It'll always do the mount-unmount-remount sequence when in Strict Mode. I suppose you could think of the first mount and unmount as the component test. You can always temporarily turn off Strict Mode to see if the behaviour of your component's useEffect is as expected and as it will be in production.
Jack, a question. It's clear for the interval and totally makes sense if you forget to properly clean-up things, but
If let's say I have a react app with react-router, and on a certain page, I want to load some data on mount (once).
If calling the function to get the data is not the correct place, then what should trigger that to fetch the data?
Right now, I can imagine stopping the first network request if it's duplicated, or not calling the request if there is some data already in the store/state, but all of that still uses useEffect
Personally, I would use React-Query. The query client is a cache. And so react-query is going to manage that. That being said, if you want to do it on your own then use an AbortController.
I think once people start to understand why this behaviour happens it's a great idea. However as you mentioned the developer experience is not great and many people are left stumped to why it happens.
This is a good development, the more quality control before shipping the better.
Really good explanation.. Thank you.....
What would you suggest for handling a scenario where you have 4 sequential service calls and have to assess where to send the user to from the various response one might get? Right now I've opted for using react-query and three different useEffects each surveying the data and error objects from those queries, but been wracking my head thinking of a better way.
If four sequential calls are required I'd just bundle them into one function, like:
async function updateUser(user) {
await fetch(...);
await fetch(...);
await fetch(...);
await fetch(...);
}
Same thing with getting data. React-Query doesn't care how many async requests are used to create the one fetch request for the RQ hook. It could be a single fetch, or a function that wraps mulitple fetchs and combines the results. Totally up to you.
Completly agree with your train of thought, however, I would not use the same name for the hook, why not use useEffectV2 ? I'm not comfortable with the idea of having two different behaviors using the same hook depending on the react version.
The behavior is the same: run once on mount. There is just now another mount in dev mode.
1:07 - i love this transition 🤭
Hello Jack,
Why not removing the strictmode, so that there is no rerendering..when we want to debug add it temporarily for debugging purpose.
Sure. Whatever works for you.
Another great video Mr. Jack. 👍🏻
Thanks for the explanation. Honestly this whole strict mode looks like a React-specific hack, a workaround. What if I have API call on component mount, would it be executed twice? So previously I could avoid state manager for a simple project, but now I can't trust React to do this job anymore because it creates unnecessary API calls
This is only in development mode. In production it would still behave the same, this is just a tool to highlight poorly written and potentially problematic react code
In concurrent mode your component can be mounted twice, yes, so you may have double API calls. It's just that it's chance-based, and strict mode helps you by making you not depend on that to see the errors occuring.
True, it triggers a double call and now it is your job to “not” update the state on an unmounted component and cancel or abort the request.
I do console log request xxxx canceled and only here I know I have cleaned up my component very well on unmount.
This is the biggest thing for me, without using a 3rd party library like React Query, what do they recommend for data fetching now? Typically people would fetch data in a `useEffect` but now under strict mode it fires the API call twice and updates state twice which seems unnecessary and a bit annoying. Sure we can probably create a custom solution to de-duplicate requests ourselves but it seems annoying that this very common flow is not already built-in. I get that strict mode is trying to show developers that this race condition may exist where your `useEffect` may execute more than once concurrently so you need to clean things up but I feel like this was already obvious...
@@gcash49 it doesn't matter at all because it's not doing it in production. It fires twice IN DEV to highlight issues
Jack will you be able to show how to work with an async API function in this scenario while using AbortController and axios ?
I'm not convinced. It seems to run twice only for a useEffect hook without dependencies and in only under strict mode in development. I want my development code to run close to my production code, not introduce side-effect that will never occur in production. I get what they're trying to do but it seems like they're introducing quite inconsistent behaviour to solve something which essentially amounts to developer sloppiness.
edit: Jack, if you're reading this I just discovered your channel and your content is great!
I am reading it and a part of me definitely agrees with you; It would be great for dev to run like prod.
Ideally, if you use the useEffect correctly, you wouldn't really need to worry about it executed twice, only if you are handling the cleanup function properly.
Often times people who are facing this issue are mostly because of they are trying to do something when a component "on mount", but here's the thing, useEffect was never meant for replacing the component lifecycle from class component. So if you try to write the useEffect with lifecycle thinking model, you will find yourself facing this issue a lot.
Every other library using the useeffect how it isn't supposed to be used has to be updated and Backward compatibility is broken for those 3rd party libraries.
I think I've misunderstood something, but how will global state libraries ensure the code runs only once? Do we move useEffect code to global store level?
Awesome video btw! I was also confused by this decision from React JS maintainers.
Yes, you would move the code that is only to be run once (e.g. connecting to an event stream) to a state store.
@@jherr How do I make sure that this code that I move to the state store, run only when a particular component is mounted? Eg: Firestore listener.
@@jherr thanks for your reply, it cleared my misunderstanding regarding this
@@jherr Yes, I also can only think up of useEffect with cleanup to trigger some event when a particular component mounts
@@jherr Could you please make a video and show an example on how to move a useeffect fetch to a global store
This was so helpful!! Thank you
I was never really convinced to replace the class based components with hooks. And I now also see why I am not gonna do it.
If it works, don't try to fix it...
Sorry my friend, it applies to `componentDidMount` as well: codesandbox.io/s/confident-golick-q9q4wi?file=/src/App.js
@@jherr Thanks Jack :)
i currently learning suspense on react 18, mr jack can you explain to us the best practice to use suspense? especially nested componets, i have problem with those, my code working but i don't think it's right 😅, btw i think its my first time to comment on your channel, ijust want to say thank you i learn a alot of things from your tutorial
Hey dear how are you doin?
This is very insightful, thank you!
Thanks a lot for this great and informative video!
In the 6:24 (NOT FIX) section, you mentioned that the place to make API calls would no longer be useEffect but state management libraries, I am having trouble finding documentation to achieve this with any state library and would greatly appreciate it if you could redirect me to any piece of information where I can get the knowledge on how to do that
Non programming related question - how did you add yourself as an overlay on top of the video? Looks very pleasing and without distractions and blends well.
Can you give a time reference?
@@jherr I mean your face on top of video. How do you do that? Do you use video editing tools for that?
@@noorkhorasi That's a green screen. My background is my actual office, but I shoot against a green screen and then replace that with a plate, and later with code so that I can do all kinds of fun video effects. I use Adobe products (Premiere and After Effects). They have a green screen keyer built in but I use a third party plugin that I like which I think produces better results. Honestly, most video editing software has chroma key removal feature, I think including OBS if you want to go full free.
@@jherr Thanks for detailed comment.
hey
Jack can you please share your VS code exenions list.
and configuion for the terminal and also your theme as well.
that auto-complete looks very cool but could not able to find it anywhere.
Thanks Jack! I like the notion of "Maybe just don't put it in the useEffect()". I seem to remember that there is some reason that one declares fetch() functions within the useEffect and not outside of it - Honestly don't quite remember why, but if you know, would that also apply to something like a subscription() function?
You definitely want to make sure that you cleanly unsubscribe if you want to put your subscription in a useEffect.
What is the extension giving him code suggestions on the fly?
I tried every kinds of hacks too. FInally, after this video I understand why. Thank you, but the point remains...
There could be a console warning in the dev mode, explaining the same. :/
Hey @jack
What about the component unmount event.
There are possibilities where you need to remove some data from the global state on component unmount event. The same data is actually being used in the current component as well.
The unmount event is modeled in the cleanup function of the useEffect.
The component is mounted, unmounted, and mounted again, in series, not in parallel. The first mounted component will not exist at the same time as the component that is mounted the second time around. So you should just make sure that whatever you put in global state is... removed, or updated, or whatever you want, in the cleanup function.
I'm angular developer programming in React 18 this is a bug and they need to fix that, Angular don't do that and I don't like that React team just put this under the rug make it's very hard to explain to team when we already know the answer. Great Video
Can you make a video for developers who are reaching 40 or more age can they stay in programming or they will be forced to do retirement after certain age
I certainly hope I don't get forced into retirement. :) I have been thinking about a video about habits to form for a long career in coding, but it wouldn't be anything related to age. IMHO you can be very early in your career and fall into a short-sighted mindset where it would be hard to get hired.
This is an issue with our industry. Some shops have become less sexist/misogynist (not all). Nearly all shops are ageist. I just (2022) turned 70. My programming chops are not the issue -- I've heard no complaints about my code/coding style.
Shops use various euphemisms -- "too senior", "too experienced for this role" -- and they all amount to the same thing. Most 30-something managers that I encounter are profoundly uncomfortable with candidates who -- in my case -- invented the technologies the managers are asking about on an interview check-list. I was part of the small cabal that created "Extreme Programming" (today we call it "Agile") -- I've been doing test-driven code since before many of today's hiring managers were born. I think the resulting "experience imbalance" is too difficult for hiring managers to embrace.
For me, there was a distinct "knee" in the curve at around 60. During my 40s, hiring managers and recruiters eagerly pursued me and it never took more than a few days to get multiple offers to choose from. That changed gradually during my 50s, and I hit a brick wall at 60 -- I was very fortunate to be hired into a role that lasted 5 years.
One comment, though -- if it is at all possible, don't let yourself be "forced to do retirement". I strongly encourage folks to do whatever they must to live sustainably without external salary -- social security, 401Ks, etc. The technical landscape today offers a myriad of marvelous alternatives for pretty much every technical choice -- nearly all very affordable. I don't self-describe as "retired". Instead, I work on what I want at the pace I want and with quality standards that I choose. I am mercifully and finally free of all those corporate meetings, "strategy presentations", HR reviews, and so on and so forth that always burn at least half of the usual work-day clock-time.
On any given day today, I write better code and have more fun doing it than I did during my last two years at a major corporation (Experian). When I choose to embrace React and NodeJS, I don't have to do battle with "corporate standards" and "IT support" to gain their permission to introduce "new" technology to a corporate infrastructure. I do occasionally have to deep-dive into issues with the support team of particular providers and that's approximately the same activity that I used to have to do with corporate IT support -- except the vendor support teams are generally more competent (with some notable exceptions). I don't EVER again have to deal with rotating Microsoft Exchange and Microsoft Sharepoint credentials.
My bottom line is that I encourage you to do whatever you are able to secure a sustainable lifestyle without a traditional employer by the time you hit 70. During that time, learn how to manage yourself. Learn what you love and what you hate on a day-to-day basis. Then celebrate your freedom on the day your social security benefits kick in.
For me, it has felt more like graduating from school than anything else. I am finally free -- utterly free -- of ridiculous and frustrating corporate "stuff". I finally have a rigorous but usually fair manager (myself). Best of all, I look forward to spending pretty much every day doing what I enjoy most in life -- coding.
Thanks, learnt a lot from your vids.
I always thought the double call was a non avoidable requirement because if the nature of the useEffect. Once the component mounts, it fires. The data may not be available yet, and if it's a argument, it fires again. That was always my thought process.
In production an empty dependency array fires only once. If it has dependency values then it fires once on startup and again whenever the values change.
@@jherr never noticed production makes a difference. I'll check that out.
Nice one, thank you so much!
Does it mean that in the production useEffect does clean up automatically? Because in the bad watch still the setinterval exist from the previous run and did not clean up
No, there is never anything automatic like that in React. If you create an interval in your effect you need to provide a cleanup function. 100% that is on you. React has no idea about what you are doing in your useEffect.
@@jherr Thanks Jack but I am confused as you mentioned in the video that in the production the StrictMode automatically is removed and based on the video (4 min:26 sec) that you showed if you remove the StrictMode the BardStopWatch and the GoodStopWatch works the same (clear the intervals in unmount mode happens automatically?)
@@sam-zy2dn Again, never any automatic in React. React does NOT know that you have created an interval in your useEffect. The reason they are the same in this case is that the stopwatches are not unmounted after they are mounted. If there was a control that flipped their visibility, that would force an unmount and the Good Stopwatch would be cleaned up properly, and the Bad Stopwatch would leak. Feel free to demonstrate this you yourself by adding a non-CSS based toggle. You'll be able to see that the Bad stopwatch continues to fire after the component has been unmounted, because React will not clear any intervals you have set.
Jack is Kevin debruyne of SWE. Have a good day!
My perhaps awful habit is to write React code based on my current understanding of approaches that work best, then rely on the several EsLint spankings to guide me towards when and where to use "useEffect" and its friend "useCallback". I love Jack's videos because they help me better understand what's actually happening as I step through things in my VSC debugger.
I do find myself pulling handlers into the top of a "useEffect" block rather than sorting out the dependency graph that results from leaving them at the top level of the component. At this very moment I'm trying to sort out "click", "blur", and "focusout" event handling so that I dismiss a pane if the user clicks anywhere outside it -- and still catch clicks from components inside the pane (be careful about "blur"!). It seems easiest to add and remove event listeners in the "useEffect" block and provide local (to the "useEffect" block) handlers for those added events. I mention this because it exemplifies the way I use "useEffect". I think my code will be unaffected by the double-pump (assuming that React is able to avoid adding and removing event listeners multiple times).
I don't mind the extra calls. I'm still not totally sure if this "double-pump" was added by design or if it is a perhaps unintended consequence of some other choice made elsewhere in React. So long as things keep working, I don't care.
It was definitely by design.
@@jherr : Cool! Just a technical nit -- when you set breakpoints inside a useEffect block (in VSC), are those breakpoints now triggered twice? You briefly observed that some of the context (ref's, for example) might be different on the second pass.
Is there specific guidance about when the second pass occurs and what might be different?
@@thomasstambaugh5181 I wouldn't spend any time thinking about first or second pass. If you are doing that then you are trying to work around this. You should write your useEffects so that run once, twice, or a thousand times shouldn't matter, they should setup and cleanup without leaks every time.
@@jherr I get that, and I'm not trying to work around it (I'm still on React 17 in fact). When I upgrade to v18 and I'm debugging a useEffect block, then I'll see each hit on a breakpoint inside the useEffect block. I'm just wondering what I can expect when I upgrade to v18.
@@thomasstambaugh5181 Gotcha. Yeah, it should definitely break twice.
Sorry but this is completely unacceptable. We are talking about lifecycle "hooks" which worked for almost 10 years without anyone being confused. React gives us components, then React is responsible to properly handle the lifecycle. Why is it acceptable for us to install third party libraries just to ensure we are only fetching a list once? This is just wrong.
It only happens, if you run strict mode, locally. The idea behind it is to help people catch issues with useEffects not cleaning up. If you don't need this feature, and want it to fire once in dev, jus remove strict mode?
Dont use strict mode thats it
@@mehdiwadoud8098 If I understood right, the strict mode will be the only mode in future react versions. You still have the chance to disable it, but not in the future versions
Cancel HTTP requests with the cleanup function?
I hv some troubles accessing it podcast
Hi sir one question, so whatever function exist in useEffect we will have to add clean up function for it ?
If it does something that requires cleanup, yes.
the only issue is now in dev environment we use double the api calls we used to do which is not something to take lightly
What about components that do API calls in useEffect and those API calls are not idempotent? Like for example a get route that also logs everytime someone requests info. It would be logging twice, wouldn't it?
I wrote a whole article about this since people are having issues with it: javascript.plainenglish.io/react-18-useeffect-double-call-for-apis-emergency-fix-724b7ee6a646 Basically there is no native "fix" in React. The `useEffectOnce` "fix" that is out there doesn't work. The best thing to do is to use something like react-query or swr which manage queries and caching outside of the context of React and therefore are immune to this "issue".
Just need a Mantine alternative or better in Vue and I may never be around react again. Been investing more and more in Vue and Nuxt 3.
But nothing is perfect.
I don't think that the double effect call should be an issue. But what I don't agree with is that moving the logic to the state solves the heavyweight issue.
The component that calls the heavy weight action, will still call it inside an `useEffect`, this is of course if it's not moved inside the state initialization (which will add that heavyweight thing regardless if it's needed), or prevent the cleanup of the state (which will leave that heavyweight state uncleaned).
So either way, you still cannot properly avoid the heavyweight functionality being called twice inside the `useEffect`.
Edit: What I find more irritating about React 18 strict mode, is that you have to upgrade to the latest version of react-router (v6), as the previous version will not work anymore. And it has a nasty issue, that it will re-render any components that uses `useNavigate` whenever the route changes, and the issue was opened from 2020, and was not fixed so far (and it doesn't seem to be the case in the near future).
In my current product I have a bunch of subscriptions that are established outside of the React context altogether at application startup time. Those subscriptions then pump data into the UI through Zustand, which has support for setting state both inside and outside of the React context.
Just disable strict mode.
If the design of useEffect, is so that you can call a bunch of actions multiple times and they can be cleaned up - and you want something only called once, and want to run strict mode - you are being encouraged architecturally to move those actions outside of the react component lifecycle, into something like a state management library, and have your components simply 'react' to state changes.
@@thorbjornbrancher5883 where should you move the initialization action for reading the data from the api, data that is needed only in a component?
Again, I don't see an issue regarding being called twice, what I'm saying is that it's not always a solution to move the things outside the effect. You should move it if it makes sense, not just to get around the double effect.
@@ionut-cristianratoi7692 In your specific use case I would 100% disable strict mode. Then I would try and further understand how to architect your specific setup.
I personally use nextJS, so I would take advantage of their i18n config in this case.
@@thorbjornbrancher5883 I understand that NextJS solves that with the page hydration mechanism, but this shouldn't be a requirement for this kind of architecture.
Regarding the disabling of strict mode, for the example with a heavyweight API call, probably there's no other way, than to just disable it. But if it's just a standard API call, I would just leave strict mode on, and cancel the request on cleanup. And each time the component is run in dev-mode, it will always cancel the first request. As the benefit of strict-mode with out-weight the downsides of the dev-mode.
Informative. Thanks
Wait, if the comp remounts doesn’t it get a separate setCount function? I get the first interval leaking but aren’t the two intervals controlling separate states? Why is the counter updating twice as fast?
Can you give me a time reference?
Hi Jack,
If I use redux with thunk would I not have to dispatch my asyn api related actions inside the useEffect? Would I not still have the same 2 call issue using state management? Thanks for video I’ve been struggling with this myself
I wasn't sold before but I am now. The only problem is that there are still wildly popular libraries (like react-beautiful-dnd) that are in sort of maintenance mode, and are broken when this is applied. It's super annoying...
This reverse compatibility issue is excellent. I hadn't thought of it from that perspective.
yes, tried it and its broken 😵💫
So using context and state manager with custom hooks(using useEffect to login into a service) would have the same "problem"?
I just turned off strict mode because they was way to confusing to me when debugging... Than again I was just starting out with react, and I'm not even sure what other benefits does strict mode have.
I started using React after 18 was already out, my website loads a KJV bible, once is enough, but loading it twice was a big headache for me.
I resorted to this, using useRef. Now I should learn to clean up. And I'm glad it's only in dev mode.
useEffect(() => {
if(!effectRan.current) {
getPosts().then(json => {
setPosts(json.books)
})
}
return () => effectRan.current = true
}, [])
Scenario: I have 2 components, 1st component has a dropzone where you can keep dropping files and it renders a list of those files using 2nd component which starts the upload onmount and shows the progress. How would I make sure that it doesn't upload it twice?
You have it properly cancel the upload in the cleanup function.
@@jherr Yep I'm aborting the request in cleanup, so it's okay to use useEffect in this case right?
@@81NARY You should be fine.
@@jherr Thank you!
What do you think about effector.dev state manager?
I've played with it, and done a video on it. I thought it was really cool. I like the event oriented style.
I'm not concvinced. Like "you cant do stuff you used to within the platform, but come on you have state managers". So you're making your framework less useful, less convenient, more confusing and unpredictable. And I don't get, what's the goal? Flaging few depreciated uses that few used
You said you were convinced. How?
They said to think of useEffect as synchronisation, but it's less useful this way for requests, as you won't want to wait twice
Thanks so much
It is still not clear to me where should I put my external API calls. In my scenario, I need to grab some data from my web service, usually, I do that inside my useEffect, there is nothing to be cleared here. Where it should goes?
javascript.plainenglish.io/react-18-useeffect-double-call-for-apis-emergency-fix-724b7ee6a646
always informational
Thanks for create and share
They should have waited to complete render-as-you-fetch before tightening the grip on strict mode. Data hydration is the big painpoint for me with this feature, because I use render-then-fetch (as I’m sure most do).
Sure, it forces me to use interceptors on my api calls, which I _guess_ is good…. Even in dev, I’m querying for user data from my cloud database, which happens twice on every page load now, even if I cancel the request in my cleanup function.
Idk, I guess I’m still not sold. I’ve already been using cleanups for web api subscriptions, etc. so this doesn’t clear it up for me :/
It looks like YT deleted my comment due to a link but have a look at issue 24553 in React repo to see perspective of complex component maintainer (AG Grid is no toy)
github.com/facebook/react/issues/24553
Is it possible to consume react npm package inside an angular application ?? . Is possible can you help me with links sir?
You could SingleSPA to embed React components in Angular. It's not trivial though and should be done with care.
To me it feels like the React team finally understood the fact that useEffect itself is hard to understand and use correctly by devs. It's not intuitive, there's too much implicity in it about what happens and how you should use it. The explicitly named lifecycle methods that we had before were easier to understand. The double calling useEffects feels like a desperate move to fix something that is broken by its core. It feels like a hack on top of something that is not working good in the first place. I see it will create many problems:
1. Performance; duplicate api calls, duplicate unnecessary renderings of components
2. Weird component flashes; components rendering twice can cause lot of visual bugs and weirdness
3. Strict mode will increase the gap between development mode and production mode. This is bad. You always want your development mode to be as similar as possible to production mode. The larger the gap, the worse. Since now you do no longer test your production code anywhere except in production. You want the code to work in dev mode exactly as it works in production to catch bugs.
4. The whole concept of 'we force you to render your components twice to teach you how to use our useEffect correctly' has something thoroughly wrong about it. If you have to go such measures, doesn't that imply that there's something too complicated about the useEffect in the first place?
great video
I'm left a little confused as to what the moral of the story is here. I understand the point that there are cases where you need to clean things up in your useEffect but most of the times you don't need to do any cleanup. Making calls to an API is one of the most common use cases of useEffect and you don't need to worry about removing a setTimeOut or anything like that.
Can we still useEffect and have confidence that it will only run once without strictmode?
Yes. You can. useEffect with an empty dependency array is run once on mount. In strict mode each component is mounted twice. In non-strict mode components are mounted just once, so the useEffect will get run just once.
Ok if fetching api in useEffect it will fetch two times how to prevent it
javascript.plainenglish.io/react-18-useeffect-double-call-for-apis-emergency-fix-724b7ee6a646
That's OK to use a state management instead of the useEffect. One question though, how the Redux possibly knows that your component is mounted and run the heavy process once on that mount, if there are no lifecycle hooks available for that and they run twice when intended run once? That's really another stick in a wheel, honestly
.
I'm not sure why redux would "know your component is mounted". You'd have to send the store you construct and action from a useEffect that you construct and then respond to it. And you could structure the logic of how you respond to it any way you choose. Your store keep track of whether or not you have the heavyweight process in flight and then ignore subsequent requests to start it.
@Jack Herrington As far as I understood the problem is that the useEffect fires twice. If you send action via useEffect, it doesn't resolve the problem, it still fires twice. If you suggest that logic of the store should track , eliminate or debounce the possible double fires, you are on a wrong way. The point of the external state management is decoupling the logic and the UI layer, the store shouldn't resolve the problems of the useEffect timing. Honestly I don't see a right solution here.
@@golden_smiles I don't see how a state manager knowing that it has a process in flight and ignoring subsequent requests to start a process is "going the wrong way".
If you change it to React.Fragment it won't go through two lifecycles on component mount.
i dont understand. how does one set state then? would have been nice if you showed an example. not just saying redux, we are using redux and i dont know how to set state after calling endpoint only once, if not for a convoluted amounts of if statements.
what am i missing here?
I'm not convinced at all about the double call of useEffect, seems very weird like devs were blowing each other minds when discussing pros and cons :) ... I like simplicity and not behaviour that doesn't make sense.
It is unusual that a library would have a "stress test" tool like this baked into it. On the plus side we can opt into and out of it. I do hope the React folks are reading the comments in here.
I thought my code is making unnecessary renders because I'm new to React lol.
It's really important to understand that a component function getting run is NOT equivalent to a DOM re-render. React is a VDOM framework. So when a component is run it generates virtual DOM elements that are then compared to the real DOM and only when there is a difference is the DOM updated. So a component can be run thousands of time and never for a DOM re-render unless the props or state change.
@@jherr It still runs unnecessary javascript comparisons that would not be needed. Also, there are cases where the dom would be different. For example if you want to show precise timing, or if your useEffect generates new values (by randomisation or by count).
@@levingy9285 You can always disable it by removing strict mode.
I'll keep using React and use the Strict Mode