You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: rfcs/2024-05-21-ui-component-model.md
+62Lines changed: 62 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -89,10 +89,72 @@ Soft goals:
89
89
90
90
When I give Claude the requirements and ask it to design a component, it usually produces something like this:
91
91
92
+
```jsx
93
+
const [count, setCount] =signal(0)
94
+
const [clicks, setClicks] =stream()
95
+
clicks.sink(_=>setCount(count() +1))
96
+
97
+
functionCounter() {
98
+
return<a onclick="{setClicks}">The count is: {count}</a>
99
+
}
100
+
```
101
+
102
+
Note the lifetimes:
103
+
104
+
- Signals are constructed once (maybe in place, or maybe imported from the runtime somehow).
105
+
- The counter function is called by the framework every time the count signal changes.
106
+
107
+
Pros and cons:
108
+
109
+
- Pro: lots of React-style functional components in the training set
110
+
- Con: JSX produces a fully dynamic VDOM. The tree can arbitrarily change across calls
92
111
112
+
Prior art:
113
+
114
+
-https://preactjs.com/blog/introducing-signals/
93
115
94
116
### Spellcaster-style functional components
95
117
118
+
[Spellcaster](https://github.com/gordonbrander/spellcaster) uses a
119
+
120
+
```js
121
+
exportfunctionCounter() {
122
+
const [count, setCount] =signal(0)
123
+
const [clicks, setClicks] =stream()
124
+
clicks.sink(_=>setCount(count() +1))
125
+
126
+
returna(
127
+
{onclick: setClicks},
128
+
text(() =>`The count is ${count()}`)
129
+
)
130
+
}
131
+
```
132
+
133
+
Note the lifetimes:
134
+
135
+
- Counter function is called once at program start, to construct the tree.
136
+
- The FRP signals create bindings to specific parts of the tree to update them reactively
137
+
138
+
The tree returned is largely static, with dynamic FRP bindings in specific places.
139
+
140
+
Pros and cons:
141
+
142
+
- Pro: vanilla JS
143
+
- Pro: static tree
144
+
- Con: less of this in the training set, but then again hyperscript is pretty common
145
+
146
+
Alternatively this lifetime semantics could be used with JSX instead of hyperscript:
147
+
148
+
```jsx
149
+
exportfunctionCounter() {
150
+
const [count, setCount] =signal(0)
151
+
const [clicks, setClicks] =stream()
152
+
clicks.sink(_=>setCount(count() +1))
153
+
154
+
return<a onclick="{setClicks}">The count is: {count}</a>
155
+
}
156
+
```
157
+
96
158
### Stateless templates
97
159
98
160
Borrowing ideas from Mustache, Vue, and Svelte, we could separate logic from template. This would make the template a pure function. It would also encourage factoring out the logic into signal transformations.
0 commit comments