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

> Vue uses a templating language closer to default HTML than to JSX, which makes it much easier to write conditionals and loops in template files, without having to reach for workarounds like map and ternaries

I like react/jsx precisely because I can use language constructs like filter, map, reduce, etc, instead of a custom implementation of basic things like if statements and loops. I find this much more ergonomic and didn’t realise some people see this as a “workaround”.

Worth also pointing out that when you write these templates, as strings or template literals, they might resemble HTML in appearance but really have no relation to actual HTML except what they output after processing. All of the added directives also have no equivalence in HTML. You’re just writing JS indirectly.



This. Most of the value-proposition of JSX is that it is just JavaScript and as such you just write code logic like you would normally do. Need to filter some items? You can do that with the Array.prototype.filter method you already know. Do you need to return a list of components based on some list of object values? Just use Array.prototype.map.

I never really understood those that see this as a weakness and would rather learn a more limited set of template string functions that work kind of like, but not entirely like, the native JavaScript collection functions.

Yes, using a ternary operator in JSX to conditionally render components/values looks a bit ugly, but nothing is stopping you from making a wrapper component like:

<If cond={...}><div>Conditional content</div></If>.

Also with JSX/TSX scopes behave exactly like they do in regular JavaScript, because it is regular JavaScript. Templating languages often invent their own form of scoping mechanism.


> nothing is stopping you from making a wrapper component like...

I'd suggest avoiding that, since the inner JX expression will be evaluated even if cond is false. In the best case this just means some unnecessary allocations, but in other cases it can cause unexpected errors (e.g. you check obj != null then try to use it inside the if).


> ... the inner JX expression will be evaluated even if cond is false.

Well, actually. it don't have to be. Just React decides to compile JSX in that way.

Vue 3 also supports JSX. But it keep the content of children lazily evaluated.

Their compiler compile a JSX `<Parent><Child /></Parent>` to structure like `h(Parent, {}, { default: () => h(Child, {}, {}) })` . So the child jsx tag is never evaluated unless the Parent component want to.

It's really not a syntax limitation because JSX never specify that the children of element must be eagerly evaluated.


> It's really not a syntax limitation because JSX never specify that the children of element must be eagerly evaluated.

That seems like a dangerous reinterpretation of JSX. It's just a literal syntax, it's not meant to be lazily evaluated.

Having a JSX compiler interpret <Parent><Child /></Parent> as h(Parent, {}, { default: () => h(Child, {}, {}) }) would be like having a JS compiler interpret

   let parent = {
     child: {}
   };
as

   let parent = {};
   Object.defineProperty(parent, 'child', { get: () => ({}) })
That's just... not what that syntax means. It should be

   h(Parent, {}, [ h(Child, {}, []) ])
Saying 'JSX doesn't specify it' feels like playing a 'there's no rule that says a dog can't play basketball' card.


It's a framework specific DSL anyway. (Unlike e4x, which is actually a standardized feature). There isn't a spec decides how it must be interpreted. And it also don't matter as long as the specific framework that use jsx output standard javascript that browser can understand.

In practice, every framework interpret jsx in slightly different way. React has own. Vue has own. Solid has own. And even react itself interpret JSX in 2 way (the new and old jsx compiler). So I feel there really isn't a rule that you can't compile jsx in some specific way because the output is never part of the specification of jsx from the beginning.


Interesting, I haven't used Vue so I wasn't aware that some frameworks do it differently.


Good point. You'd have to pass the stuff to be rendered as a function that would be run if the conditional is true. In any case you just add another allocation, scope (the anonymous function), etc. But some people might like the "syntax" a bit better.


Yeah you have to do

  <If cond={...} then={() => 
    ...
  } els={() => 
    ...
  } />
so the `then` and `els` branches only get evaluated if needed


We use ternary extensively with in JSX. Keeps the logic in vanilla JS

{ some_condition ? (

  <H2>It was true</H2>
) : (

  <H2>It was false</H2>

)


Even though I'm a JS programmer myself and I do use similar constructs once in a while, I have to admit that this gets dangerously close to the Greenspun's tenth rule... In times like this I miss proper Lisp macros.


Which has ugly untax IMO


> Yes, using a ternary operator in JSX to conditionally render components/values looks a bit ugly, but nothing is stopping you from making a wrapper component like:

Couldn't you put that in a function that returns the correct JSX element or am I misunderstanding the problem? Something like:

  renderThing(number) {
    if(number > 0) return <div>...</div>
    return <div>...</div>
  }


  const Page = () => {
    return <div>{renderThing(someNumber)}</div>
  }

Simple ternaries are fine IMO but thats what I do when the logic gets complicated. I never used a nested ternary in that situation, for example.


You have to be careful with code like the above in React. Using a lower-cased function that returns JSX but is not rendered with react.createElement (either directly or via the JSX syntax) can lead to confusing violations of the rules of hooks as it relates to exact ordering of calls.

This is because it doesn't get registered as it's own component, so conditionally called children with hooks may cause errors.


The render function is a pure function returning jsx based on the input, not invoking any stateful operation like "functional hook".

So this style of code is fine in react


Does simply uppercasing it avoid these concerns?


Plus, the power of being able to treat JSX as any other JS object means that you can use standard JS constructs like loops - slightly contrived example:

  const items = [];
  let runningTotal = 0;
  for (const item of someArray) {
    runningTotal += item;
    items.push(<li>Item {item}; running total {runningTotal}</li>);
  }
  return (<ul>{items}</ul>);
The closest example I can find in Vue would require a computed property to implement something like this.


Disagree. I would argue your example is hard to read compared to the equivalent in Vue, and it mixes business logic (computing the running total) with the rendering logic.

  <script setup>
    const items = [1,2,3,4,5,6]
    let runningTotal = 0

    const getRunningTotal = (item) => {
      runningTotal += item
      return runningTotal
    }
  </script>

  <template>
    <ul>
      <li v-for="item in items">
        Item {{item}}; running total {{ getRunningTotal(item) }}
      </li>
    </ul>
  </template>
No need for a computed property. Plus, getRunningTotal can be unit tested, or extracted to another file for reusability.


You've still mixed the logic, just in a horrendously oblique manner. If you rendered the list twice the second list's running totals would be wrong from re-use of the global variable (in what is meant to be render-only logic).

If you're after keeping the concerns separate you would need to precompute the running total for each item.

See also: mustache(5) which completely embodies this philosophy.


Extracting function to separate fine in react would be equally easy . You just extract and import it.

It is just that above example is so short and readable, that you don't have to bother.


Does syntax highlighting or lsp stuff work for things like v-for?


Yep. There's a vscode extension.


I don't think this is a good way to build JSX from lists. Better to keep components smaller. Also this way will show React linting rules, like the "key" requirement.

  return (
    <ul>
      {someArray.map((item, idx) => (
         <li key={item.id}>Item {item}; running total {idx + 1}</li>
      )}
    </ul>
  );


It's technically possible, but it looks horrible and should be avoided because of lack of readability. Keep the templates plain and simple, and store your business logic elsewhere.


I liked JSX a lot when I was using React. However, writing business or view logic in templates is a maintainability nightmare. With JSX it's very tempting to do this and I did this often, but it's still a mistake and I regretted it every time I visited my spaghetti JSX months later.

When it comes to comparing React with Vue or Svelte, the templating is not the critical factor.


The JSX bits in a React codebase aren't templates, at least in the traditional sense where a template is a static file that looks like some desired runtime output and contains some "slots" which are analyzed at build time (or program start time) and then filled in with dynamic values at runtime. JSX kinda looks like that, but there is actually no "templatey" stuff happening at build time, i.e. React does absolutely no analysis whatsoever of your JSX and has no idea what it contains until each new time a component renders at runtime.


Stricly speaking it's a render function indeed, but it does serve the same functional purpose as what people usually call "templates", i.e. defining a dynamic view only once.


That’s true, but the technical differences between a render function and a traditional template is arguably the biggest fundamental difference between React and most other UI rendering tools.


I totally agree. Templating is not the critical factor indeed. The templates shouldn't contain business logic so they should be simple by default. If not then you're following an anti-pattern.


I get using plain JS, but JS's lack of expression-statements (see rust for contrast) just makes most of it EXTREMELY awkward.

Ternaries, booleans that cast to JSX, switch statements wrapped in IIFs...


Once you try any languages where (almost) anything is an expression, it is hard to accept statement-oriented languages


That's true. But in JSX you have the extra constraint that you can't really use imperative code so this magnifies even more.


Indeed, having if-then-else being an expression (as well as switch) would be great in JSX. It seems there's a proposal for a match expression in TC39...


The crazy part is that there's not a really good reason why we couldn't make if..else function as either a statement or expression depending on the context. I think there's a proposal to do that.


Indeed, at least there's a TC39 proposal for that. It should be the default for all statements and it's shocking that python went to define the new match clause to be just a statement and not an expression


This discussion never ends. It's so subjective and totally not important at all. Templates shouldn't contain complex logic anyway, only formatting logic with some for loops. You can learn any syntax in 30 minutes if needed. The battle isn't fought on the hills of templating logic. It's sad because there are many interesting differences other than templating logic between frameworks, but they are less superficial so they get little attention.


But you want to avoid using to much code in HTML, because this isn't "page.php?page_id=welcome" anymore..


Especially with copilot, which is clearly well trained on React and JS, I find I often just need to write the first few characters of an array method or other common method and it will generate 10 or so LOC that are at least 90% of what I want.


In practice with Vue you tend to write that stuff in JavaScript (eg in a computed property) and keep the HTML as simple as possible.

I've done a lot of Vue and your bit of React and overall I prefer the Vue way here.


You know you can use JSX with Vue right?

https://vuejs.org/guide/extras/render-function.html


GP was reacting to this statement from the article:

> Vue uses a templating language closer to default HTML than to JSX, which makes it much easier to write conditionals and loops in template files


In defense of those directives and template languages, they compile down to efficient operations that every developer can take advantage from. I like that `v-for` is likely more efficient in regards to how it operates than how an average developer might write such a function, especially when dealing with nested data or more complex situations. Other efficiencies can be gained by using a template language as well via the compiler.

Not that you can't with JSX (Solid and Qwik use JSX and have transparent ways of doing optimizations as consumer of those frameworks) but its not currently the default, most (if not all) optimizations must be done "by hand", is a big tradeoff for some places.


This can be the case, but as I understand it typically isn't so, at least with most big frameworks. For example, I believe Vue templates are typically translated to a hyperscript-like render function that has a similar efficiency to the average React render function. Indeed if anything, I would imagine Vue would be slightly less performant, because the v-for loop is quite abstract and can handle things like looping through objects, so there must be a reasonable amount of machinery to handle all the different loop cases.

The state of the art is less about handling things like loops, and more about reducing the amount of work needed to render static elements. For example, say you have a single component that renders a static table, and in each cell of the table you need to render something dynamic. In the classic vdom system, you'd construct a `table` node, with a `tbody` child, which in turn has `tr` children, which was contain `td` nodes, and then finally in the `td` nodes you render the dynamic content. This works, but most of the content isn't actually changing, only the contents of the `td` nodes. What modern frameworks like Solid and Svelte do is to compile that whole nest of nodes into a single HTML string, and then add instructions that specify where exactly the dynamic content lives. That way, on the initial render, the browser is doing more work natively, and on later updates, only the new content needs to be checked and changed. I know there's a library for React that adds similar capabilities there, albeit with a few more constraints than in other frameworks.

I do know Solid does for-loops differently than in other frameworks, but this is less to do with efficiencies gained by compiling, and more about how to optimally use the signals system that it uses for reactivity. Apart from that, I don't really know of any optimisations that would make something like `v-for` any faster than `.map(...)`.


the Vue compiler does do optimizations you can't get if you were to write the components by hand, most of the time.

I did only use `v-for` as an example of sorts though, and in the common case, `v-for` vs a regular `for` loop are similar if not the same, IIRC, but in some cases where your children may show or hide based on downstream data, it can be more efficient




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: