Hacker News new | past | comments | ask | show | jobs | submit login
PSA: React 18 calls code twice in strict dev mode to detect side effects (reactjs.org)
135 points by tomduncalf on April 10, 2022 | hide | past | favorite | 125 comments



> In React 17, React automatically modifies the console methods like console.log() to silence the logs in the second call to lifecycle functions. However, it may cause undesired behavior in certain cases where a workaround can be used.

I feel like when you've gotten to the point that something like this has been proposed and accepted as a good solution to a problem your framework is facing, it may be a good time to stop and reconsider the approach of the framework.


This gets at something deeper: React has a policy of “in the dev environment anything goes; we will mess with your code and its runtime performance to help detect bugs or future bugs; you want us to do this, even if you think you don’t.”

But this assumes good QA and staging environments exist and are used correctly. In reality, many users of React test on local and immediately deploy into production. The more the environments differ, the less friendly React is to these users. Timing issues and race conditions may surface in production. And thank goodness this isn’t Python where a log statement can consume an iterable if you allow it to do so!

And for those saying “Strict Mode is opt-in” - your coworker may opt in your whole app without you knowing it. Hopefully you see the PR or the Slack thread. So much in React now enables this “spooky action at a distance.”

The React team has put a lot of thought into balancing the performance needs of large codebases with the stability needs of smaller teams with less robust SDLC. I can’t think of a better workaround. But it’s still going to cause chaos in the wild.


I agree with the sentiment of not being comfortable with dev and prod differents.

That said, with React these dev mode differences are intentionally about making obscure production issues (such as timing ones) rear their ugly heads in development. The goal is that if your code works without issues in dev, it’ll work even better in production. It’s a thin line for sure, but I broadly support the way they’ve done it so far.


can be solved this way:

- npm start when developing

- deploy on dev using the artefacts from npm run build

builds take a bit longer this way, but it guarantees QA will test using a non-dev build


> In reality, many users of React test on local and immediately deploy into production.

> deploy on dev using the artefacts from npm run build

These two statements do not fit together.

I agree that "You should have dev/test/staging/... environments" is the correct answer, but clearly that's not the reality for everyone.


> clearly that's not the reality for everyone

might not be the reality, but multiple envs is the only correct answer.


Broadly speaking I think React is in a weird spot where they have painted themselves into a corner with no obvious way of fixing it by essentially forking the DOM and doing so many things independently of the wider web platform. That approach made a lot of sense when it was first released but is just a liability at this point.

If you’re deep in React land and it’s all you know I think 2022 might be a good time to expand your horizons a bit because the landscape around you has changed a lot in the past five years.


> Broadly speaking I think React is in a weird spot where they have painted themselves into a corner with no obvious way of fixing it by essentially forking the DOM and doing so many things independently of the wider web platform. That approach made a lot of sense when it was first released but is just a liability at this point.

The problems that strict mode is addressing with this somewhat unusual approach have absolutely nothing to do with the VDOM. Rather it is that code using React is subject to restrictions (being pure functions and following the hook rules when using hooks) that are impossible to express or enforce at compile time in javascript.


Sorry just to be clear, I wasn’t tying this to the strict mode situation but was attaching myself to the concept that this is just one of several points where the framework is showing some signs that it’s time to start thinking about alternatives particularly because I don’t think some of them are fixable at this point, they are just too central to the entire project and those decisions no longer make sense.


Outside of Vue, and maybe Angular, are there any other stable alternatives with a decent ecosystem? I'd love to hop off the React train, but I haven't found anything that compares to the experience of just using create-react-app with Typescript support.


Try solid.js [1]

I have been using it for a month now and love it. If you are coming from react the API is familiar enough that you can get productive in a day or two. Reliance on observables is a big plus for me (no virtual dom diffing) and the dom reconciliation is very similar to lit. Check out the author's blog posts [2] for more details.

If are into jamstack, Astro [3] has good support for solidjs already and offers an easy way for selective hydration of dynamic parts of the UI.

The component ecosystem is a bit lacking compared to react/vue, but it pairs well with pure css libraries like bulma/daisyui or webcomponent libraries like ionic/shoelace.

And you can also wrap your solid components as web components and use them in a larger app without converting it all to use solidjs.

[1] https://www.solidjs.com/

[2] https://ryansolid.medium.com/

[3] https://astro.build/


RiotJS and SvelteJS get mentioned as alternates in my circles. I like Riot - but only done it on smaller projects.


If you haven't check out ember-cli + ember.js latest Octane release. Full typescript support, thriving community, lots of companies using it, lots of active development.


Any thoughts about [Lit](https://lit.dev/)?


For whatever it is worth this is the one I am betting on.


Aside from the bustling ecosystem, Surplus has been around for a long time, consistently beats benchmarks, and is quite lightweight and unopinionated. I've used it for a lot of projects, small and large, quite successfully.


Have you checked out https://mithril.js.org/


I remember Ember being solid for a while, but I fell off of the front-end stuff


When React first came out, it was a breath of fresh air. There were some weird kinks, but instead of getting better they doubled down on the magic, and it got worse over time.

I would really like something like React, but completely explicit - no hidden state, no hooks, no monkey patching. Everything class based, you have one render method, one method where you can launch your ajax, and you give your data dependencies explicitly instead of React trying to infer something and calling your functions at random.


> Everything class based, you have one render method, one method where you can launch your ajax, and you give your data dependencies explicitly instead of React trying to infer something and calling your functions at random.

Class based components in React got pretty close. But for whatever reason, everyone jumped on the hooks bandwagon, against which i have some personal objections: https://blog.kronis.dev/everything%20is%20broken/modern-reac... (harder to debug, weird render loop issues, the dev tools are not quite there yet)

That said, using the Composition API in Vue feels easier and somehow more stable, especially with the simple Pinia stores for data vs something like Vuex or Redux.


Reginald Braithwaite had some really great responses to the move away from OOP as well: [0]http://raganwald.com/2016/07/16/why-are-mixins-considered-ha... [1]http://raganwald.com/2016/07/20/prefer-composition-to-inheri...


It would be enough for functional components to have extensible input and outputs

    function Button({props,ref,key,hooks}){
      useEffect(hooks,()=>{...})
      return {render: "text", ...stuff}
    }


Yeah come on, the global hidden variables are completely unnecessary.


You may just want HTMX, right?


It's not a "solution". It's more akin to a lint rule imho. Javascript provides no language level guarantees. There is no static type checker or compiler to enforce these things. So we rely on linters, tests, and assertions. Yay dynamic languages.


Thank you for the feedback. I agree this behavior was confusing. (We changed it to slightly dimming the second log in response to the community discussion. This change is released in React 18.) The new behavior seems like the tradeoff we dislike the least but new ideas are always welcome.

Overall, we’ve found that calling some methods twice is a crude but effective way to surface a class of bugs early. I absolutely agree that it’s not the best possible way to do that, and we’re always thinking about ways to surface that earlier — for example, at the compile time. But for now, the current solution is the best we have found in practice.


Thanks for clarifying Dan. I think it might be appropriate for React to console.warn that strict mode is active (in dev mode) with a short description of this side effect, or perhaps the “dimmed” log message could have an explanation after it. Not all users have explicitly enabled strict mode (e.g. in my case I just started a new Next.js project) so this behaviour can be quite surprising and hard to track down why it’s happening.


The problem with logging a message is that it creates permanent console noise for people who enable it, thereby incentivising people not to. It seems like a small thing but people are very sensitive to extra logs. And if you allow silencing the log, we’re back to where we were.


I guess I was imagining a single warning message at the top, “React is running in strict mode. This may result in you seeing console log messages twice. Read more here. Click here to disable this message for this site. Click here to disable this message globally”. Not too much noise really, especially if you can disable it per site or globally.

I do see where you are coming from, I’m just thinking of my experience where I spent 30 mins+ thinking I’d found a bug or fundamentally misunderstood React all these years or whatever, and it turned out it was just the strict mode - but because I was using Next.js I never explicitly opted in, so had no way of knowing this might start happening (unless I read every release note). I’m guessing a lot of other developers using Next might be similarly confused!


I agree, at first reading this sounds just plain horrible. I haven't tried doing any research, can anyone point out why it's not?


Afaik this has been the behavior of StrictMode since it was introduced in React 16.

One thing that’s called out in the linked docs is that duplicate console.logs were _deliberately_ silenced in React 17. I have no idea what they were thinking when they made this decision, but it sounds like it has been walked back in 18.


Monkey-patching console.log sounds so hacky..

> In React 17, React automatically modifies the console methods like console.log() to silence the logs in the second call to lifecycle functions. However, it may cause undesired behavior in certain cases where a workaround can be used.

> Starting from React 18, React does not suppress any logs. However, if you have React DevTools installed, the logs from the second call will appear slightly dimmed. React DevTools also offers a setting (off by default) to suppress them completely.


Also, these types of global modifications make such libraries fundamentally incompatible with projects such as Tauri that focuse on safety and security. In a recent video of theirs they mentioned that of the popular frameworks, the only one that didn't seem to do any dodgy modifications of the global scope was Svelte (they didn't mention which frameworks failed the test, but I imagine React was one of them).


It’s totally opt in, and in development only, so react doesn’t prevent you from using that other lib


It is, I have lost tens of hours to this over the last couple years.


Interesting and an odd choice of behaviour in 17! I tested in a codesandbox with Next.js using React 17 and 18 and observed that only 18 did the double logging I was seeing, so assumed it was new behaviour in 18. Actually I guess I was seeing 17 silencing the double log.


React also already ran components twice when devtools is open, even without strict mode. This happens in my React 16 codebase with silenced console.log and no StrictMode in sight.


I think you mean it logged log messages twice?

I don’t believe having devtools opens changes the runtime semantics of the app.that would defeat the point of the devtools.

I do know it annoyingly logs things twice


It doesn't log things twice, because DevTools replaces `console.log` and similar with no-op versions when they re-play the render. But it does call your component more times than you expect to power the DevTools hook inspector and other features.

Here's the code that turns off `console.log`: https://github.com/facebook/react/blob/b8cfda15e1232554487c7...


I haven’t seen anything about devtools altering runtime semantics but I may be wrong, that is something I think I disagree with because of the possibility to have bugs that go away when trying to debug


The hacker news post doesn’t even link to the article about what’s new in react 18: https://reactjs.org/blog/2022/03/29/react-v18.html#new-stric...

> To help surface these issues, React 18 introduces a new development-only check to Strict Mode. This new check will automatically unmount and remount every component, whenever a component mounts for the first time, restoring the previous state on the second mount.


It used to call render twice, now it runs effects twice also.


It was like this even before strict mode was introduced.


I recently wasted time figuring out why my code was getting executed twice and found this out the hard way. I think this is a particularly good example of overreach by Javascript developers and at the very least a console.warn could have notified me of this. I just removed strict mode as i think this is an awful side effect to implement. In my case, instead of helping me find bugs it had me hunting non-existent bugs, sigh.


I thought I’d share this in the hope that other developers see it and don’t lose a bunch of time wondering why e.g. code in a useEffect(…, []) block is being called twice.

I created a new Next.js project and was very confused to see my console.logs appearing twice. It might be nice for React to log a warning that it is going to do this as it’s quite confusing if you aren’t aware of it!


> code in a useEffect(…, []) block is being called twice

Shouldn't that be one of the few cases where the code isn't being called twice? useEffect is meant for side-effects, so it isn't included in the list of functions that React will call twice.


This new check is in preparation for an upcoming feature that lets you preserve state between unmounts. For example, when switching a between routes or changing a top-level tab. The check simulates unmounting and immediately remounting (with state/DOM preserved), which is why effects run twice. It simulates what happens when you switch away to another tab and then back, like a stress-test for this scenario. Since in most cases, switching to another tab and then immediately switching back shouldn’t be observable behavior. You might fire an extra impression log in development, but from the user perspective the behavior should be the same. And if it’s not, you’ll see the same result as if the user actually switched tabs there and back. So it doesn’t just “run the code twice” but it simulates what happens when a tree remounts with existing state. Most components are already resilient to this, but the feature is hard to adopt if this resiliency isn’t being tested. This check helps find the remaining cases where remounting wouldn’t be safe, early.

Hope this clarifies it a bit!

https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.h...


We already have Providers for that.


this sounds similar to angular which performs multiple passes in dev mode and warns if values have not settled


This seems like a super aggressive move, giving up lots of performance & complexity for some pretty com ppl lex consistency checking.

Is tbis in production build too?


No, this is document as only occurring in development mode.


Yea sadly there weren’t enough characters in the title field for me to put “strict dev mode” so that nuance was lost

Edit: dang updated the post title to include this


Aside from being development-only, note that you also need to wrap a component in `<React.StrictMode>…</React.StrictMode>` to opt it into this.


Yeah, good point - I thought it could be that Next.js changed their default behaviour to use strict mode when they upgraded to React 18 but another comment says React 17 silenced the duplicate logs(!) so maybe the change is older than that.


> This only applies to development mode.


dang was kind enough to update the post title for me to make this clear!


If they don't want people to just end up depending on this behavior in a stateful way instead they should actually deliberately rely on non-determinism, call the functions a small random number of times.


It's not meant to thwart adversarial cases or situations where programmers are trying to "trick" strict mode. It's a safety net for those who know the "rules" of react, but still might accidentally introduce side effects and want to catch it.


Even just as a safety-net, there's precedent for this. Golang intentionally randomizes hashmap key iteration order to prevent people from relying on it: https://stackoverflow.com/questions/9619479/go-what-determin...


The fact that so many devs think react is a fundamental part of browser based applications has really pushed me away from front end. I used it for years and I just don't see it.


This, 100%. I love doing UX/UI work but everyone (I've worked with) is always pushing to use React for everything and it has led me to moving to more of a back-end / full-stack role over the last few years.

A job I recently left was building a B2B site where customers could log in and order files that they needed printed & delivered. The back-end was going to be Laravel but instead of simply using Blade (Laravel's PHP templating engine) we had to make a RESTful API so we could use NextJS and React. IMHO it was beyond overkill for a site where users would basically just be checking boxes and clicking an "order" button.

I just assume nowadays that whenever anyone pushes for React, NextJS, or any AWS Lambda based over-engineered auto scaling microservice solution to a simple problem they're just looking to pad their resume before jumping to their next job.


Same boat here. Once you go Vue you never go back. Miss me with hooks.


Vue was a stepping stone to Svelte, once you try it you never go back ;)


Really? I've seen it a couple times here but I wasn't really sold on it. Vue to me is already top tier, what does Svelte do even better? Would love to give it a shot at some point but not really dying to experiment outside of work right now.


oh god, the horror of the fact that this is necessary! As someone who has largely and happily sidestepped the whole reactivity thing for the last decade, it really sounds like that whole world is starting to implode and contradict the very things it promised in the first place (simplicity). Please let web assembly deliver us out of this js-ridden mess \o/


It's not reactivity that's the problem, it's React. The way svelte and solid.js do it is simpler. Things only run once unless explicitly made reactive. And there is no virtual DOM.


Unpopular opinion: I took a look at Svelte. Was immediately disappointed that I can’t just drop it in an existing website.

All these frameworks assume you’re writing stuff from scratch. Most commercial software, both internal and external facing, have legacy to deal with.

Even with a brand new app, you have to succumb to npm/webpack/babel stuff. It feels like building a castle on stilts. Inspires confidence, it does not. Back to jQuery I guess.


You're looking for Vue. It calls itself The Progressive Framework and the title fits.

The thing about Vue is that it spans the whole spectrum of a simple <script> tag à la jQuery all the way up to a fullstack app with server side rendering, jsx & typescript support, IDE plugin, browser debugger, and build system.

But the *great* thing about Vue is that you can start off with the simple <script> tag and add it to an existing project (built with other frameworks) and slowly build up to more Vue features if/as you need them.

It's learning curve is also incredibly smooth so you can ramp up the features to your specific needs.

Some examples:

- There's multiple well respected guides and video series out there to port old legacy enterprise Angular.js applications to Vue.js bit-by-bit until only Vue.js remains

- Laravel (the well known backend php system) has decided to use Vue for it's front-end integrations.

- Wikimedia (the foundation that runs Wikipedia) has decided to adopt Vue.


I was looking at Alpine.js but Vue is even better! Thanks.


You can just drop it in. The API allows you to expose any components or code you compile which can be called/created/deleted as regular javascript objects


Maybe checkout lit-html[0]. It doesn't use a virtual DOM, it can be dropped into existing projects, it powers Google's Lit Elements[1], and if you want stateful components you can implement yourself pretty easily[2].

0: https://www.npmjs.com/package/lit-html

1: https://lit.dev/

2: https://github.com/codewithkyle/supercomponent/blob/master/s...


> I can’t just drop it in an existing website.

I mean.. should you though?


SolidJS looks amazing. I'm seriously considering trying it out for my next project.


I just visited their web page and I had to laugh at the fact that preact is faster than React in their benchmarks... I used preact for hobby projects to avoid the horror of JS build systems. I didn't know that this is going to get me more performance.


I'm a skeptic of the promises of reactivity and a fan of web assembly, but the main reason reactivity is a pain is because UIs are inherently a painful domain, not because of JS itself.


> UIs are inherently a painful domain

No they aren't. Developers think their a painful domain because they are the ones that introduce the complexity in the name of the customer who doesn't care, to increase the developers salary in some kind of crazy Ponzi scheme.


I’ve been working on UIs for 15 years and when I read comments like this I have to wonder if you’ve worked on complex, stateful, feature-rich UIs. The potential for bugs to appear is almost exponential as you add layers, and it isn’t really the fault of the developer so much as the nature of nested behaviours. This is true in any environment, but easier to manage when human beings aren’t the ones executing your code in non-deterministic ways in variable execution settings.

The tools we have in the browser are excellent up to a point. I think the challenge comes when you need to create reusable abstractions around them several layers deep.

There are tools which help manage these challenges really well, like state charts, but they aren’t perfect and they come with their own challenges. The reality (I think) is that UIs can present quite incredible complexity, and creating tools with approachable APIs to help tame the complexity is a legitimately huge challenge.

It could be that I’m a bad software developer (most days I’m pretty sure there’s some truth in that), but I’m passionate and spend a lot of time deep in this space and exploring ways to make it better. It isn’t rocket science, but it isn’t digging holes either. The react team is a bunch of smart people and they’re doing good work on solving a tough challenge.

I don’t see a Ponzi scheme at all. Sorry if I’ve missed some sarcasm or something here - feel free to disregard if that’s the case (or if it isn’t, too)


Text alone is already a painful domain [1][2] and text is just a small subset of the full UI domain.

--

[1] https://gankra.github.io/blah/text-hates-you/

[2] https://lord.io/text-editing-hates-you-too/


One thing I've found is that things used to be a lot simpler. We've added tons of complexity in the last 15 years, but the fundamentals of web pages and the UI controls in them largely have stayed the same. We've largely moved backwards. And what's worse, I can't even hire junior devs who know how to do things the old simple way anymore. It's framework or bust now.


Web browsers have had callbacks for DOM elements since... forever. Why did we need to add an entire component framework like React on top of it?

Everything on a web page does not need to be interactive. It's a document first.

Web applications are cool. Maybe React makes sense there. _But every site does not need to be a web application!_ And yet somehow, React and company became the industry default.


I agree with you to the extent that components = interactive. But there are other benefits of a component model, even for pages which are mostly static. They allow you to develop the same page and its various (reusable) parts with the same code for rendering the static parts and the dynamic parts. This is especially nice on sites where the dynamic-to-static ratio may vary significantly between pages, or between areas of the same page.

This use case hasn’t been particularly well supported by many component libraries (React among them; Marko being a long time notable exception), but it’s an area that’s currently having a bit of a renaissance: there is of course Marko which has supported this model for years, joined by other notable frameworks like Astro and Qwik. Even React is moving more in this direction with Server Components, just targeting other use cases.

The component model will continue to thrive, not because everything is interactive, but because components are an excellent abstraction for developing for the web (and a lot of other formats).


React doesn't have to be your whole website. Even the starter tutorial in the docs starts off by showing you how to just add in React through a CDN and make a react app as a single component of a bigger webpage

Obviously that's not at all how it's used in practice (or even in the create-react-app template), but I do think there's a place for something like React


Others are right to point out that this isn’t a problem with reactivity. But there’s an even more important correction here: React, perhaps in spite of its name, isn’t actually (fully) reactive. And while that’s sort of an academic nuance[1], it’s the underlying reason for implementing things like this.

1: https://dev.to/this-is-learning/how-react-isn-t-reactive-and...


I'm glad I'm not the only one who sees this.

Are the people building React completely oblivious to the nigh-unbearable code smell that this is? Why is it so difficult to reason about whether or not code will have side effects?

I'm no frontend developer, and certainly don't have experience with React, but after stopping in at their homepage to see what it does for me and finding out about "JSX syntax"... jesus. I don't know how you parse something like JSX, but I would be willing to bet the implementation is a dumpster fire of completely unnecessary complexity.

I would really like to believe that the people building this stuff aren't amateurs, but the more I learn, the more convinced I am that this is the case. The modern web is bloated, slow, and riddled an assortment of issues that is different depending on which site you're on. Will my back button work this time? It's anybody's guess!

It only seems appropriate to lay the blame at the feet of those who thought the best course of action was to make web development ten times more complicated than it needs to be.


> Are the people building React completely oblivious

Perhaps the people criticizing it so flagrantly are oblivious to the goals motivating their design choices.

No one is forcing you to use it.


> No one is forcing you to use it.

Kinda depends on where you work / what you do.


Blame the employer (or yourself for not switching) if it’s really that unbearable, it’s not the React team’s fault


> it’s not the React team’s fault

I wasn't intending to imply that it was the React team's fault.

Personally, I like React and think it has its uses. I was loosely referencing an old coworker who was successfully and comfortably using jQuery for over a decade.

> Blame the employer

I do. They wanted cheaper labour so they had a revolving door of junior developers straight out of online React boot camps and since it's all they know it's what they used on every project regardless of other technologies that were a better fit. Turnover can be expensive so the company caved in and turned every project into a React project.

> or yourself for not switching

Sometimes easier said than done. It can be hard for some people to up and leave when they like their boss/company that they've worked with for 20+ years.


> Why is it so difficult to reason about whether or not code will have side effects?

I’m not sure exactly what you mean here, but I can’t think of any reasonable way to write a JavaScript framework that invokes developers’ JS code containing functions, closures, etc. and makes it simple to reason about whether that code will have side effects. This seems like a basic consequence of Rice’s theorem. I suppose you could have a compiler that only supports a strict subset of JavaScript and makes side effects easier to reason about, but arguably that would just be its own separate language altogether.


So, how would you, in JS, go about ensuring the code people are writing is side-effect free? Specifically.


You just use PureScript instead of ES2056 or whatever.


I wouldn't.


To further restrict these component methods from having side effects, could React call these methods using a Proxy or eval() context that blocks these methods from reading or setting variables in the global context?


Would be extremely hard, especially given we're not just talking about core APIs like fetch: React code uses closures like crazy, and you couldn't wrap and probably couldn't eval-shadow every single object in scope that might get mutated

You might be able to catch some common cases, but that might give a false sense of security

Enforcing against side-effects in JavaScript is pretty much a lost cause. Even merely accessing a property can cause side-effects, thanks to getters and proxies


Blazor does something like this but for different reasons (ServerPrerendered mode for lower latency UX).

It took me a solid day to realize the behavior was intentional. There were no problems but it was one of those "I cannot build an empire on these uncertain foundations" moments.


If anyone is curious as to why, I believe it's the only way that React can "poke" your code to see whether it really is side-effect free, and therefore concurrent mode/suspense compatible. The idea is that React can re-render your component whenever and however often it likes whilst getting the same results for the same input state, without this assumption, new patterns such as concurrent mode and suspense become very difficult to implement. Double rendering is a rudimentary dev-time test to see whether the output is actually the same to try and help you avoid bugs later on (data races for example), without enforcing a language, such as ReasonML or Elm. Alternatives would require really complex static analysis or strict ESLint rules. There may be other reasons as well.

Sometimes there's a need for side effects, the DOM is very stateful and unfortunately React is not quite fast enough for smooth animations at 60fps on most devices, it's also a lot easier to use global variables (no judgement) rather than properly organising state hooks and component props.

React started to move away from OOP and more towards FP, starting with hooks and function components. One of the driving reasons behind this was that function components could be minified a lot better than classes. Reducers, side effects, pure, memo, are terms that are more known in the FP land. I also think it gave them a lot more control as a framework to implement patterns such as concurrent mode as functions are stateless unlike classes, moving the state up into the React framework itself. This means several versions of the state can exist at once, and React just runs them through your function to generate the view. Side effects introduce unpredictability and nondeterminism using this pattern.

This FP style can be confusing to new programmers (anyone feel like trying to explain useEffect() to a 5-year-old? Anyone?), especially those that are used to global variables or manipulating the DOM directly (JQuery), but understanding the OOP render cycle had its own learning curve. Frameworks such as Elm are met with much love, even if React's hook-based approach is a little different.

Small aside, I also think that's where useEffect() got it's name from: side effects. It's where you put all those nasty network calls and setTimeout()s, and then scratch your head when you forgot to cancel/unregister them when the component unmounts and React complains that you tried to change the state on an unmounted componment. Suspense (hence the need for side-effect free functions, hence this double-rendering problem) should help with avoiding putting "if (stillMounted) { ... }" everywhere in useEffects with async code by giving React more control over the render/update process.

Full disclaimer, I haven't actually written React in a while, not since I found out about Svelte, I'm curious, how to authors of libraries such as React/Framer Motion handle the double rendering issue when interacting with the DOM directly? Other frameworks that I know of that avoid the complexities of concurrent mode/suspense either very stricly enforce this FP style, such as Elm, or try to be fast enough to forgo the virtual DOM and embrace mutable state, events and two-way data binding such as Solid and Svelte.


> React started to move away from OOP and more towards FP

Please don't confuse what you see in React with FP! It is not FP. See:

https://mckoder.medium.com/why-react-is-not-functional-b1ed1...


It seems to me like this is just arguing that react is not purely functional. That doesn't disagree with what the other poster is saying which is that react is moving towards a more functional style.


> more functional style

What does "functional style" mean here? Is C language a functional programming language? It lets you write functions, pass functions around as parameters, and so on. So, is C functional?


Without closures it's a stretch, but yes I would say you can write in a functional style in basically any language.


I would argue that other than eschewing classes for bare functions, there is nothing functional (as in "Functional Programming") about React or hooks. Simply removing classes and calling it "functional" is a stretch.


They didn't call it "functional" though. They simply said that it is more functional than it was previously. If you reserve the word "functional" for only the most idealistic implementations of those ideas then it just makes it unnecessarily difficult to describe things which are in the middle.

Basically, I think "functional" is more of an axis than it is a circle on a Venn diagram.


> They didn't call it "functional" though.

See [1] where they say "if you’re a functional programming purist and feel uneasy about React relying on mutable state as an implementation detail, you might find it satisfactory that handling Hooks could be implemented in a pure way using algebraic effects".

[1] https://medium.com/@dan_abramov/making-sense-of-react-hooks-...


never mutate anything and just compose functions and your C is functional


Effect, State etc are monads, and 'use' is do-notation that lets you use them in an imperative style. What's not functional about that?


Excellent synopsis.

> React complains that you tried to change the state on an unmounted componment.

They actually got rid of that in the new react :)

> handle the double rendering issue when interacting with the DOM directly

I think the idea is whatever they do to the DOM needs to be idempotent. Those should be using useLayoutEffect usually.


Related:

I have an outstanding Bounty on a SO question for how to write a reusable useRef hook that only runs on the very first mount under StrictMode conditions:

https://stackoverflow.com/questions/71695213/equivalent-isfi...


ITT a bunch of clowns who don't know anything about React, haven't written a single line of it in their lives and don't care one whit for spending 10 seconds to understand why this is a useful feature, or how it isn't even a new feature.

Never change, HN.



That sounds really reactionary!


Um, I remember StrictMode was running the code twice since forever. Probably since the time it was introduced in React 16-something. Has anything changed in React 18?


Yes, they used suppressed the double logging with the double render, but now in 18 they show the second logging as well, but with dimmed colors:

https://twitter.com/dan_abramov/status/1507750167390400512


Off topic but anyway To all react devs, If you are not using web components (not mutually exclusively) then you are doing it wrong.


Pretty sure its been doing this in dev mode since 0.14. Maybe earlier...


Yeah I think what might be going on is a combination of Next.js switching to strict mode at some point, and React 17 hiding the double logs.

I’d never seen the behaviour before (but had never explicitly used strict mode - to be honest I didn’t know it existed!) and switching between React 17 and 18 was enough to make it happen, so I assumed that was the responsible change, but actually it’s a bit more subtle.

Thought it might be useful to share for people who are using Next.js anyway, as for me it just started happening when I created a new project with no explanation which led to me thinking I was losing it for a while, lol.


the hacker news title just isn’t precise about what part of it changed and doesn’t even link to the relevant article

https://reactjs.org/blog/2022/03/29/react-v18.html#new-stric...


This, while unexpected, is not the end of the world.


It already did that since v16


I actually wish more languages did this kind of thing down to the compiler level. I see a lot of C code especially go through an "evolution" where it starts out being compatible with only one platform (typically x64) and then it slooooowly acquires wider compatibility one issue ticket at a time.

Wouldn't it be great if all that english text in the language standard documents were enforced and/or exercised at both compile time and (dev) runtime?

Instead of just "dev" and "release", I would love to see the default be "evil".

As in... in "evil" mode the compiler will abuse every rule, randomise everything that is not explicitly specified, and run your code on a virtual machine that has 19 bit ints, 23-bit pointers, bizarre memory models, or whatever to make sure that your code is truly robust, not just "mostly robust", which is like being "almost pregnant".

For a real life example, there was a bug lurking in the Java standard library (and several other languages!) where "sort()" wouldn't work on maximum-length arrays because they used the naive (a+b)/2 algorithm to find the mid-point of a segment and hit an integer overflow.

If there was an evil runtime with tiny integer sizes, they could have hit this with small array sizes and realised their mistake early instead of shipping broken code that blows up and crashes on the biggest and hence most important servers in the world... sometimes.

Taken to the n-th degree, haven't you wondered how many similar bugs lurk in standard libraries? Which "algorithms" work on max-length arrays? Which only work on MAX/2? Which on MAX/4? Which on (MAX/8)-53? Who knows! I don't. You don't either. Some or all of these could blow up in your face at the worst possible time and you have no way to test this[1].

An evil VM could be devised to test things like:

"Throw any exception that could be triggered a small percentage of the time, or at command".

"Pretend memory is far more constrained than on the specific physical host where the code is being developed."

"Introduce network latency, UDP packet reordering, random packet drops, and every possible IO error that the host operating system might throw."

"Use a different memory consistency model to the current physical CPU."

"Pause threads randomly, and otherwise randomize timing and interleaving behaviour to the maximum extent allowed by the spec."

"Simulate processors with different bitness, such as combinations of integer size vs pointer size."

"If the spec doesn't require any particular boolean representation, then run the code with different ones randomly. E.g.: 1, -1, and even random non-zero values for true."

"Database queries that don't specify the sort order are often returned reversed or randomized."

"i18n settings that aren't explicitly specified are randomized. Your UI language is Turkish, the keyboard is French, and the region is Japan."

"All external environment variables are randomized and/or substituted with similar but potentially invalid values. You must explicitly specify the whitelist of environment variables that you require to be stable."[2]

[1] Except for running code intended for 64-bit in 32-bit mode and testing with 2-4GB data sizes. However, there are other potential issues for which such tricks don't work. Anyway, this is just a "poor man's evil VM". What you want is a full flexible evil VM that can constrain anything.

[2] Sounds like a pain in the backside for you? Now put yourself in the shoes of the poor admin that has to make this stupid thing work from a compiled binary 17 years later and has to reverse engineer the possible environment variables using a hex editor and a glass of scotch.


CASS: Chaos as a service


Well that explains a lot of things.


Pontificating a little here, but it reminds me of "The road to hell is paved with good intentions" quote.

Any external code that purports to be reusable should not be concerned with the idea of an "environment".

Positing that reducers should be pure is fine and dandy, telling me I can't throw in a side effect is none of your business.

Instead of running it twice, just make a warning log and be done with it.


> Positing that reducers should be pure is fine and dandy, telling me I can't throw in a side effect is none of your business.

API contracts work in both ways. The user has to uphold it just as much as the provider. If you don't breakage ensues. In lower-level languages this can include the nasal demons from UB.


It can't log a warning because it can't actually detect side-effects. The only way to "detect" them is to push them to cause breakage in the app logic


With React, it's your code that is the external code. Your reason is quite sound. Your reducers shouldn't be concerned with any jind of "environment" or side effects.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: