5 ms·
I don't particularly like how control logic needs to be embedded within JSX using ?ternary : operators and .map(() => stuff) within the HTML. Also, in order to
by vanviegen 1y ago
I don't particularly like how control logic needs to be embedded within JSX using ?ternary : operators and .map(() => stuff) within the HTML.
Also, in order to transform JSX into individual rerunnable functions, we'd need a whole different transpiler. I like being able to code browser-runnable JavaScript directly.
To each their own. :-)
- CooCooCaCha 1y agoYou don't have to do that in the html if you don't want to. You can easily assign those operations to a variable then insert the variable into the html.
- WorldMaker 1y ago> Also, in order to transform JSX into individual rerunnable functions, we'd need a whole different transpiler. I don't think you would. `<Component prop="example" />` gets converted by current transpilers into `jsx(Component, { prop: "example" })`. The `Component` itself is passed as is. In the case of Components that are just functions, that passes the function as-is, as a function you can just call as needed. JSX was built for "rerunnable functions". It's a lot of how React works under the hood.
- vanviegen 1y agoThe problem is that JSX transpilers will put child nodes in an array, instead of in an anonymous function, meaning there is no easy way (without transpiler magic) to rerender just a part of the component. This JSX: <section><h1>Welcome</h1>{data.enabled ? <input /> : "disabled"}</section> Which becomes this with Babel: _jsx("section", {children: [ _jsx("h1", {children: "Welcome"}), data.enabled ? _jsx("input", {}) : "disabled" ]}) But we'd need something like this to fit Aberdeen: _jsx("section", ()=>{ _jsx("h1", ()=>{_jsx("Welcome");}); if (data.enabled) _jsx("input", {}) else _jsx("disabled"); }}) In React you can, with some effort, limit virtual DOM rerenders to a single component. Aberdeen rerenders fractions of components by default, if that's all that needs to happen. That's why it works well operating directly on the actual DOM, without a virtual DOM inbetween.
- WorldMaker 1y agoYour `_jsx` function can auto-wrap children in a function. Also, you can just pass functions as children, too if you really want to make the JSX author work for it: <section><h1>Welcome</h1>{ () => data.enabled ? <input /> : "disabled" }</section> That doesn't even look half bad to me. It looks really close to many of your other examples. > In React you can, with some effort, limit virtual DOM rerenders to a single component. Aberdeen rerenders fractions of components by default, if that's all that needs to happen. That's why it works well operating directly on the actual DOM, without a virtual DOM inbetween. A lot of that depends on what your model of a "component" is. React will rerender fractions of a component in advanced areas such as a Error Boundaries and Suspense. Also, for what little it is worth, my JSX-based library isn't a virtual DOM, operates directly on the actual DOM, and generally renders components once and only once in their lifetime, because it binds all changes even more directly to specific DOM properties.
- MrJohz 1y ago> Your `_jsx` function can auto-wrap children in a function. It unfortunately can't, because by the time the jsx function gets a chance to run, the expression has already been evaluated, whereas the whole point of a framework like this is to be able to run that evaluation repeatedly. So what you'd need to write to get that to work would be something like <div>{() => user.name}</div> for every single case where you're interpolating a value, which starts looking kind of ugly. It also has its own pitfalls. For example, your example with a ternary in it would unnecessarily rerender (i.e. completely unmount and recreate) the child elements if the input changes but the conditional still evaluates to the same thing. (E.g. if data.enabled was 1 and we set it to 2, what we want is to have no change in the DOM, but what we'd get the input element being unmounted and remounted.) There's also just the general issue that JSX requires some sort of transform. This isn't necessarily bad - I use SolidJS a lot which explicitly makes use of the chance to optimise the JSX rendering at compile time - but there are situations where you want to avoid that, and having a syntax that's focused on the "no compile step" case is useful.
- ibash 1y agoModern react developers forget that if statements exist. When react was class based it was trivial to do: render() { if (this.dontNeedToRender) { return null } } Now, because hooks can't be skipped, react developers jump through many hoops to use an if statement during rendering.
- gavinray 1y agoYou can just write an IIFE expression, and use regular imperative logic like if/else and switch statements. If you find the syntax ugly, you can create a function like "run(expr)" to wrap it, similar to Kotlin's method of the same thing. <div> {(() => { switch (status) { case Status.LOADING: return <div className="loading">Loading...</div> case Status.ERROR: return <div className="error">Error: {error.message}</div> case Status.SUCCESS: return <MyComponent data={data} /> } })()} </div>
- i_dont_know_any 1y agore: syntax, I agree, it's stopped me from ever trying React/JSX-based frameworks, which I am sure is an over-reaction. I have a POC syntax extension (babel parser fork) I named JSXG where I introduced "generator elements" which treats the body of the element as a JS generator function that yields JSX elements. The simple/naive implementation of just running the generator was okay, but I (perhaps prematurely) worried that it would be not ideal to have the resulting list of child elements be actually dynamic-- as opposed to being fixed size but have false/null in place of "empty" slots and also using arrays for lists made by loops. So, I also had a transform that followed conditional branching and loops etc. and made a template of "slots" and that resulted in a stable count of children, and that improved things a whole lot. It's been a while since I revisited that, I should try and find it! Comparisons below. Aberdeen: $('div', () => { if (user.loggedIn) { $('button.outline:Logout', { click: () => user.loggedIn = false }); } else { $('button:Login', { click: () => user.loggedIn = true }); } }); $('div.row.wide', {$marginTop: '1em'}, () => { $('div.box:By key', () => { onEach(pairs, (value, key) => { $(`li:${key}: ${value}`) }); }) $('div.box:By desc value', () => { onEach(pairs, (value, key) => { $(`li:${key}: ${value}`) }, value => invertString(value)); }) }) JSX: <div> {user.loggedIn ? ( <button className="outline" onClick={() => user.loggedIn = false} > Logout </button> ) : ( <button onClick={() => user.loggedIn = true}> Login </button> )} </div> <div className="row wide" style={{ marginTop: '1em' }} > <div className="box"> By key <ul> {Object.entries(pairs).map(([key, value]) => ( <li key={key}> {key}: {value} </li> ))} </ul> </div> <div className="box"> By desc value <ul> {Object.entries(pairs).map(([key, value]) => ( <li key={key}> {key}: {invertString(value)} </li> ))} </ul> </div> </div> JSXG: <*div> if (user.loggedIn) { yield <button className="outline" onClick={() => user.loggedIn = false} > Logout </button> } else { yield <button onClick={() => user.loggedIn = true}> Login </button> } </*div> <div className="row wide" style={{ marginTop: '1em' }} > <div className="box"> By key <*ul> for (const [key, value] of Object.entries(pairs)) { yield <li key={key}> {key}: {value} </li> } </*ul> </div> <div className="box"> By desc value <*ul> for (const [key, value] of Object.entries(pairs)) { yield <li key={key}> {key}: {invertString(value)} </li> } </*ul> </div> </div> Edit: Come to think of it, I think it may have been <div*>...</div*> or even (:O gasp) <div*>...</div>.
- recursive 1y ago> I don't particularly like how control logic needs to be embedded within JSX using ?ternary : operators and .map(() => stuff) within the HTML. It doesn't. In my[1] framework, there is JSX, but control flow like map is done with a function. <ul> { ForEach(model, item => <li>Fruit: { item }</li>) } </ul> There is a lambda there, yes, but at the top level it's a ForEach() function call. Likewise, it is possible to use get conditional elements in JSX without using react's ugly approach. [1] https://mutraction.dev/ https://mutraction.dev/