This proposal looks to simplify/remove control flow by leveraging Solid's own Component API. Instead of writing:
<$ each={ state.list }>{ item => item }</$>
You'd write
<For each={( state.list )}>{ item => item}</For>
Or if you didn't want to use control flow you could use functional underpinnings that could apply to more than just Rendering:
map(() => state.list, item => item)
Please leave any feedback below. I'd love to have feedback on any of the pieces I am proposing here from syntax to overall objective.
When I initially implemented Control Flow it was for many reasons:
Ironically all 3 ended up being sort of mute:
In addition this approach had these additional problems:
$. It just can't handle that as an intrinsic element. Typing in general is a lot looser when I have a generic flow element.By changing this anyone will be able to create their own Control Flow or not so we can handle scenarios that today I cannot anticipate. And it should reduce overall library size from the reduction of complexity in the Control Flow themselves.
moduleName configuration option.props.children accessor will run the children code.Provide will not be a Built In but rather exported on the Context object the way it works in React.
For
<For
each={( state.list )}
fallback={( <div>Loading...</div> )}
>{ item =>
<div>{ item }</div>
}</For>
Show
<Show
when={( state.count > 0 )}
fallback={( <div>Loading...</div> )}
>
<div>My Content</div>
</Show>
Switch
<Switch fallback={( <div>Not Found</div> )}>
<Match when={( state.route === 'home' )}><Home /></Match>
<Match when={( state.route === 'settings' )}><Settings /></Match>
</Switch>
Portal
<Portal anchor={document.getElementById('modal')}>
<div>My Content</div>
</Portal>
Suspense
<Suspense fallback={( <div>Loading...</div> )}>
<AsyncComponent />
</Suspense>
There are a couple drawbacks:
$ was tighter syntax lending to less verbose code. You could instantly identify control flow on the page. Without pre-compilation we want separate imports (and works better with TypeScript).{( )}. Pre-compilation knew exactly which attributes were dynamic. Now that this has opened up you need to specify.It is a breaking change across all libraries. And will be released as a new minor version (since there is no major version). For the most part this will be a simple code change to make in existing Solid code.
In general I'm not a fan of the "Everything is a component" philosophy and when components become more than just pieces of UI.
Disregarding personal preference I think changing from $ to explicitly named tags like For and Switch has a benefit of making initial reasoning of what the pieces of code do a bit quicker.
But it's such a small syntactic change that the benefit mostly comes from the clear namings suggested than anything else.
So my two cents are that if it improves Solid then go for it. 馃憤
The biggest benefit is perhaps this opens up people writing their own components that control downstream templating or not use Components at all. This opens up just using functions again and benefitting from optimized reconciliation. I still believe that for fine grained due to all the wrapping of accessors and deferred evaluation into computed contexts that Components or special directive-like helpers abstracts those details for beginners better since they provide a syntax that avoids that. So Components because of JSX.
Popular fine grained libraries don't let you wrap your own which set a precedence I was following in the name of optimization which didn't completely pan out. I will be performance tuning this approach to ensure we do not take a hit. But these helpers have a lot of functionality baked in for that reason that complicates and bloats unnecessarily for common cases. Components give a homogeneous way to offer different or extended functionality that has minimal impact on the consumer. Whether you use this For component or someone else's ForBetter component it's a simple swap.
I think this looks great! One of my nit-picks about Solid was this kind of weird <$> control flow that has limited TS support and discoverability.
I personally like the React way using .map, ternaries and && since they are simply part of the language but this proposal actually makes me think these control flow components are the way to go. Routers tend to come with a <Switch> component, <Portal> and <Suspense> have to be components anyways so making <For> and <Map> seems logical. Plus you get niceties like a fallback option. Additionally, if this reduces Solid's complexity and file size, that sounds like a win.
It would be great to just use map and ternaries but there are complexities with reactive contexts that make this not the most optimal approach. Mostly since we are making real DOM nodes you can't just careless map the whole list. You need to use a memoized map. Ternaries are fine they just put all children in a tracking context. Also if the ternary is based on a condition, ie. state.count > 5, everytime count updates it will re-evaluate the children. You can solve this by hoisting the children out of the condition, but control flow handles this all for you.
In any case, I'm happy to announce this has now been implemented and released with v0.9.0.
I've submitted to the JS Framework Benchmark the numbers look promising.

I would love to write:
<for each={ state.list } item={ item }>
{ item }
</for>
<for each={ state.list } item={ { index, value } }>
{ index } : { value }
</for>
@threeid The primary effect of the change in this RFC is control flow is no longer pre-compiled. They are just normal components. In so they cannot support special syntax that knows their behavior. So a syntax like this is unlikely without the possibility of indicating that the property is an argument and a way of indicating argument order. I suspect the resulting syntax might be more verbose and less obvious.
Ok closing this. It's been a month now. So I think the discussion is done on this.
Most helpful comment
I've submitted to the JS Framework Benchmark the numbers look promising.
