Not sure I understand this, or if I do understand it, I definitely don't agree. HTML's a tree. Function calls are a tree. They're similar in nature and they map cleanly to each other.
> Or how you can’t use some standard HTML attributes in JSX (because JSX doesn’t know the difference between a React prop and an HTML attribute). Or memoization. Or how there aren’t real conditionals, so you have to rely on short-circuit operators. Or how preventing infinite loops is your responsibility—even though there aren’t really loops, so you have to use array methods…you know what, let’s just move on.
These are natural consequences of representing HTML as code, and they help me understand the first quote a bit better. I still don't think JSX is bad. Putting flow control into the template language in the style of Vue, Angular, or even the supposedly logicless Mustache ends in a programming style that I dislike, where the dividing line between template logic and logic in the actual code isn't clear, and you need to refactor heavily when you reach the gaps in what the template language lets you do.
They're closer to failures of EcmaScript. Coffeescript and Ruby weren't ideal, but their syntactic sugar would have let you do (in ES-like pseudocode):
const TodosList = ({ todos }) => (
<div class="todo-list">
{
if (todos.length > 0) {
todos.map(t => <Todo key={t.id} todo={t} />);
} else {
<p>No todos yet</p>
}
}
</div>
);
Blending code and data can look a bit scary, but it lets you copy the blocks of code around like normal. You could (in a theoretical world where if statements returned the result of the last line of the branch) just copy that code outside the JSX, and have it work properly. With horrible JSX ternary operators you still have to rewrite, but that's the fault of the JS part of JSX not the underlying language-agnostic concept, and it's still something I prefer to putting logic in the template language itself.