Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

So JSX is pure Javascript and not, say, a dialect of XML embedded in JS? Because it sure looks like the former even though it compiles to the latter.

React isn't Javascript. It's a franken-language that looks superficially like a mix of JavaScript and XML whilst following the rules of neither. That's why there is such a thing as a React compiler - a good sign that you're not writing JS, which doesn't have compilers.

The other hint should be all the new rules you have to follow. React is full of magic syntax that looks like functions, but e.g. you can't call them inside an if statement, or you have to redundantly declare the 'dependencies' (variables you read) and so on. The semantics of React code are very different to imperative straight line code.



> So JSX is pure Javascript and not, say, a dialect of XML embedded in JS?

It would be best to think of it as syntax sugar for create Element() function calls. You enter JSX with angle tags and insert expressions in braces

> React is full of magic syntax that looks like functions, but e.g. you can't call them inside an if statement, or you have to redundantly declare the 'dependencies' (variables you read) and so on

That's not magic syntax. That's just functions that must be processed in regular order between render ticks.

It's not a difficult exercise to write a "plain JS" function that works that way. If you've worked much with closures you can visualise how that would play out.


Hooks are magic syntax without any doubt. All magic syntax is made up of non-magic parts, that's kinda the point.

The way you know it's magic is it shatters the principle of referential identity, which tells you that a variable is itself. It pretends you can use a simpler mental model but you really cannot and must not.


Hooks aren't magic syntax. The problem with hooks has nothing to do with syntax. The problem is that the React crowd has decided to overload the meaning of a term that has had a reasonably solid interpretation (at least in comparison to the React crowd).

"React Functional Components" have nothing to do with conventional functional programming. They inherently (intentionally?) violate the spirit of functional programming through hidden global variables, while pretending that it is still functional, when in reality they should be doing the opposite. They should be upfront about the hack that hooks are. They are not functional, they are merely functions. In all other respects they operate as if the function was a method inside a class and that all hook calls are with respect to an invisible "this" keyword that contains the component's context. Since hooks are not named (which would expose their inherently pseudo-OOP nature), they associate their state through a hidden incrementing counter. It's like you're sweeping all the OOP parts under the rug to pretend to be functional so you can be a cool functional hippie too.


Aren't hooks just composable effects implemented in userland? In fact, Sebastian actually asked the ECMAScript committee for effects a la OCaml 5.0 effects (https://ocaml.org/manual/5.0/effects.html) and React only built their own when the committee said "not right now", if I remember correctly.

The thing is ... you can model effects with the Free monad (or with Haskell's Backpack as was on here just the other day - https://news.ycombinator.com/item?id=45221112), so they are definitely "functional", for most variations on the definition of "functional" that I know.


Yes, that's exactly it. React is presented as functional but it's still just stateful components, except instead of OOP syntax and features making that clear, it's hidden away so that it looks functional without actually being so.

This happens because GUIs are inherently imperative constructs.


> They are not functional, they are merely functions.

Functional literally means dealing with functions composition.

Free of side effect is not a property of functional programming. Ocaml is functional and has side effects.


Please, just give me objects back. They were so much easier to reason about. I liked writing `this.stateVar`!


What makes it even worse is that in order to match the hidden state with the output of a render function, it has to be "reconciled" which uses usually-right heuristics to match the tree structure of the function output to the tree structure in the fiber cache.


Yeah, well put tech wise (the ad personam part puts me off a bit, though). Personally I like hooks quite a lot, but e.g. I feel I have to check once a month or two if a memoized component (that’s „functional” in name) re-renders if its props stay the same and the only change is the state..


You can write const [a, b] = useState('x') in vanilla js and typescript. Hence it is not magic syntax.


Yeah, that's vanilla syntax. The semantics are fairly magic though. The component function that calls useState though isn't a normal function, it's a function that must be called in a special way by the React runtime in order to line up all of the hidden state that React maintains so that it can magically infer the data that your `useState` call maps to and then there's more magic to maintain the lifetime of that data.


Some of you are really going out of your way to make this more complicated than it is.

Next you're going to complain about the fact that the compiler handles static variables with controlled allocations for you in C.

Like there's no rational basis for your complaints or critique other than grandstanding.


Yes, but it is not syntax. It's a contract with the library. React is completely usable using vanilla JS syntax. Same cannot be said for Vue and Angular. It feels a bit like talking about apples and oranges in this thread.


Your example usage only implies what I would consider the non-magic implementation behavior. I could fulfill that contract with `(initial) => { let s = initial; return [ s, v => s = v]; }`. No hidden magic there, and no chance of breaking referential identity.


> The way you know it's magic is it shatters the principle of referential identity, which tells you that a variable is itself

When you do a useValue() it is clear you are grasping at something with a larger lifespan than your function.

Conceptually it is not much different than

    int counter() {
      static int x = 1;
      return x++;
    }
Which predates C89, if age is an argument


> It would be best to think of it as syntax sugar for create Element() function calls

Thats what makes it a new language. C is just sugar on top of assembly.

Its so strange that jsx needs a buildstep, but misses ton of obvious ergonomics that one could have added. Why className instead of class? With a buildstep, it would surely be possible to determine if class was a keyword or not based on context


> Thats what makes it a new language. C is just sugar on top of assembly.

I think that's a bad example. C isn't a sugar for assembly: For example what assembly code does a function prototype desugar into? Sugars have 1:1 mappings with host code

Maybe you're just being rhetorical about the spectrum of macros, sugars, and languages, though.

(In my opinion, a better target for that criticism, in JS land, is the Jest test framework, because of all the reordering magic it does that break fundamental ES semantics)

> Why className instead of class?

This hasn't been a constraint since... I want to say React 18, six or seven years ago? I might be misremembering the history but I think that was only a problem in the Early Days when there was paranoia about whether JSX needed to be conservative with reserved keywords


Syntax sugar is language syntax that improves a common pattern from the language (making it sweater). jsx, async/await - things that just abstract common patterns.


> It would be best to think of it as syntax sugar for create Element() function calls

More like syntax cilantro. Some people love it. Some can't stand it.


> That's why there is such a thing as a React compiler - a good sign that you're not writing JS, which doesn't have compilers.

You say that like it's a bad thing - but it didn't stop Babel or TypeScript from being popular, both of which need a compiler. And being honest, I don't like extra tools in my chain, which is probably why I don't use React proper, but that proves you don't need anything React specific for anything other than optimisation

The only syntax you really want for React is JSX. Which is just because writing React.createElement("div" ...) every time is unergomomic. JSX isn't specific to React. It could easily be a language feature, in fact it is an OOTB language feature of TypeScript.

> React is full of magic syntax that looks like functions, but e.g. you can't call them inside an if statement

They look like function calls, because they are. They're not "magic syntax", and in fact, those rules are explicitly because theres no way around that without implementing special syntax


JSX isn't and hasn't even been necessary to use React. The first version of my company's site didn't have a build step and called createElement manually.

And in the decade I've been writing for React, I've never used the React compiler. But saying that it's proof that it's not JavaScript it's like saying that V8 is proof that JavaScript is too complicated because otherwise it would be fast enough not to need a JIT.

And all those rules? You don't have to follow them either. Use class components. They're still there, and they work fine.


If you also have experience using JSX in a React app, I'd love to hear any opinions/experiences you have with doing the JSX style vs createElement() style coding.

I understand how they map to each other but I've only done JSX. That said, I'm old so calling functions all over the place is in my wheelhouse, and I'd love to hear from folks who have done both.


It's verbose, but it's not all that bad for small applications. Especially when you don't want a build step or tooling. In today's day and age, you can have your favorite LLM do the verbose parts for you if you really want.


I'm a fan of this lib [0] (with some personal modifications). It's prefer it over JSX, but I use JSX because it's usually simpler.

0: https://github.com/sultan99/react-on-lambda


> So JSX is pure Javascript and not, say, a dialect of XML embedded in JS?

This is actually the selling point to me. As someone who started learning pure HTML, JSX just makes a lot of sense to me intuitively. It feels like intelligent HTML


JSX is just a syntax extension to JS, and it's not even required to create a React app.

React "compiler" is in fact a transpiler, which is a very common thing in JS.

>React is full of magic syntax that looks like functions

Full of magic syntax meaning 5 straightforward hooks? Surely they are not true free-form JavaScript, but at least the syntax itself is not turned into a DSL


Nitpick: React compiler is not a transpiler. JSX needs to be transpiled, and that's usually done by TS compiler. React compiler is another optional thing on top that's relatively very recent.

https://react.dev/learn/react-compiler/introduction#what-doe...


All compilers translate one language to another language. Historically compilers targeted lower-abstraction languages than the source language. "Transpiler" is a compiler whose input and output abstraction levels are similar.

The React cinematic universe has a habit of repurposing existing terminology, but they're both transpilers, to the extent that "transpiler" is even a word.


You are absolutely right! (Here I'm roleplaying an AI chat bot which caught red handed hallucinating).

It appears that I was wrong about the definition of transpilation. It's a specific term for a compiler that compiles from a high-level language to another high-level language, even when those languages are the same with no DSL and even when the logic is optimized.

I stand corrected.


In JS land, transpile was used to distinguish something like elm->JS from ES6->ES3. One was the same language with different versions and the other was different source languages.

Yes, all transpilers are compilers, but not all compilers are transpilers.


> 5 straightforward hooks

`useEffect` is straightforward? Cloudflare recently (like, literally 4 days ago)[1] had a pretty big outage because of the improper use of `useEffect` (surprise, surprise, it was the dependency array), a hook so infamous if you search "When should I use `useEffect`" you'll get approximately 9 trillion hits, with nearly all of them telling you something different, including Dan Abramov himself having to chip in with multiple blog posts telling people to NOT use it because of how much of a dumpster fire of a API it is.

[1] https://blog.cloudflare.com/deep-dive-into-cloudflares-sept-...


Well, that is really embarrassing for Cloudflare... A recursion in a side-effect via dependencies is a rookie mistake, it's hard to imagine it could slip into production with a proper due process. Maybe they should stop vibe-coding and deploying things to production without any tests or review?


If after nearly a decade swarms of people are still making the exact same mistakes with how they use a specific method exposed by the library, then the problem isn't with the hundreds/thousands of people making the mistake, the design of the method is broken. This type of issue simply does not exist in Vue or Svelte even if people abuse watchers (which I've anecdotally noticed tends to happen from React devs writing Vue code).

Also I just want to point out again that Dan Abramov had to write an insanely long guide to using useEffect [1]. This piece is around 10k words explaining in-depth how useEffect works. That is insane for one of the fundamental, core methods exposed by a library.

[1] https://overreacted.io/a-complete-guide-to-useeffect/


You know for thousands of years people are still stepping on rake, the spikey part. And they get hit in their foreheads. The rake is lever by design, but I wouldn't say the problem is the rake.


I've spent more hours using rakes than `useEffect()`, but I've only had the problem with one of them.


A) exactly how many people in alk of history have ever actually done that?

B) rakes can't be changed to prevent that, software apis can.


Disagree about it being a rookie mistake. In the simple case, yes. But consider data used by an effect could travel all the way from root to the max depth of your tree with any component along the way modifying it, potentially introducing unstable references. Maybe it worked when you tested. But later someone introduced a new component anywhere between data source and effect which modified the data before passing it on. That component may have used useMemo. So it looks ok, but it over fires.

You become reliant on all your ancestors doing the right thing, in every situation, forevermore. One mistake and unstable references cascade everywhere. The surface for introducing errors is huge, esp in a large, complex codebase. And we have no way to guarantee a stable reference.


>But consider data modified

This is why we never modify data but create new data. Data must be immutable. Strictly typed. Always in the form it is expected to be. Otherwise - crash immediatelly.

>But later someone introduced

This is why we write integration tests. Introducing anything without tests is only guesswork.


Sorry I should have been more precise. I don't mean mutation, but taking the data and producing a new (potentially unstable) reference to pass on. Mutating data in react results in under not over firing.

It is practically impossible to have full coverage of all code paths in integration tests, since there is a combinatorial explosion of paths. In a case where you have 3 components each with 3 paths you have 27 unique paths. And no app is that simple in practice. It gets out of hand quickly.


As a rookie with gray hair I completely agree :)


Javascript has warts, React has warts, Svelte has warts, Python has warts... It's easy to shoot yourself in the foot in any tech - it's leaky abstractions all the way down after all.

useEffect usage needs to die, yes. I don't think it's a case against React, given its age.

Otherwise, using React is straightforward. I started coding in it without reading any docs. As someone who used Dojo, prototype, ext.js, jQuery (+UI), Backbone.js, knockout (still has a special place), Mithril, the classic angular, vue (2), svelte, Marko and even Solid (I'm not totally sold on signals), React is the most straightforward by a mile.

Is it the most performant? Hell no. Is it the one with the least gotchas/warts? Nope. Concise? A giant no. Batteries included? It depends on what you're looking for...

But I can just be productive with it, and it makes sense.


A child who hasn't tasted other mom's food always say, my mom is the best cook in the world.

You saying you can be productive in react is just ironic. I just read it as, I can be employable using React.


My brain does this sometimes, sorry :) I meant to say, "I can just be productive immediately in React". Not going to edit though.

edit: also about the moms cooking analogy... With many of those libs/frameworks, I have much more experience with than react.


We need to determine which framework is most productive while suffering from Mommy brain.


You like jokes


Bro lists like 8 different moms whose food he has, then says he likes react-moms food, and you make it sound like that's the only thing he's ever had. Did you even read the comment you replied to?


>The semantics of React code are very different to imperative straight line code.

Yes and all you have to do is learn why those semantics exist in order to do react well.

Unfortunately too many programmers still think they can just mimic other code to figure it out.


JSX is how someone who knows only HTML and no programming languages would go about writing some Javascript. Which is a good thing IMO.


I can’t recall a single time where I would want to put JSX in an „if” statement.. In fact I can’t recall a single time where I would want to use JSX in a different context than the return value of a render phase.

So from my personal experience the things you mentioned are non-issues in practice. Do you have a different experience?


I was actually meaning the hooks and memoization stuff not JSX. I think JSX can be put inside conditional logic and loops.


Ah OK, I see it now—I focused too much on the „magic syntax”.

As for hooks, I guess I mentally treat them as magic that lives in its own lane, and so I've never really thought that I could do anything with them, other than what the manual prescribes.


yes


Everything has compilers now and we definitely want to go that direction. The no build people aren’t close to building any popular consensus, like not close at all. Even plain JS is compile heavy because browsers are just compile targets.


> Even plain JS is compile heavy because browsers are just compile targets.

No. Plain JS requires no compilation.


um....react is literally js and its not a language, you can write react with or without jsx which is just syntax sugar to make it look more like html.


“syntax sugar” means its a new language. It has a new syntax.


This is the first time I've seen someone argue that adding syntactic sugar means creating a new language.


it really depends on how much syntactic sugar you add.

You could go back 13 years, show somebody some JSX and ask them what language they think it is and nobody would be well that's obviously JavaScript with a bit of sugar on top.


Sure, if I'd been replying to a comment that had anything resembling nuance, that would be applicable.

It did not.


So Python with type definitions (syntax sugar) is a new language?


They should call it Typhon




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

Search: