-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't wire the wires? #9
Comments
Hey @mindplay-dk, you are correct that's a major feature lacking in alfama. My plan is to add the following features to wires
onMount(() => {
wire(($) => {
// ... todo
}).run();
});
Opened #10 to handle these features With regards to naming, I really like the name wire because it makes it explicit that you are wiring reactivity to the dom. But I did a quick search and solid uses the effect/memo/computed terminology. I do like the fact that this differentiation makes it explicit that effects are actions & have no value, while memo has return value. Maybe alfama should also have a such a distinction and introduce effect, while keeping wire as memo? EDIT: come to think of it, are effects without value useful? Having values make it easy to prevent multiple execution of of a effect by just having a look at previousValue. Without values you have to hoist a variable in outer scope and then remember to set it manually. Also I see in solid computed doesn't allow setting a signal. Is that really usefull? EDIT2: How about making it more like haptic with computed signals? So you can pass a wire while creating a signal instead of making wire a function that accepts a token? |
Short answer: I would shoot for as much parity with something existing, either Solid or Sinuous. Long answer: ... 😅 Having a single abstract "wire" concept that can be used both for effects and computed state, it's tempting, in the same way that consolidating anything is tempting - and, if it makes sense, I think it's fine to consolidate it that way internally. But people are going to use this for two different purposes, and it's helpful to have language in the source code explaining the difference - so I would prefer having two separate functions for derived state and effects. It sounds like you're leaning that way anyhow. From my date-picker example in Sinuous, here's an example of derived state: export const DatePicker = ({ /* ... */ }) => {
const offset = observable(0);
const date = computed(() => {
const d = new Date(value());
d.setMonth(d.getMonth() + offset());
return date;
});
const month = computed(() => months[date().getMonth()])
// ...
} The important difference I'm hoping to see here is explicit subscriptions: export const DatePicker = ({ value, /* ... */ }, { observable, computed }) => {
const offset = observable(0);
const date = computed(($) => {
const d = new Date(value());
d.setMonth(d.getMonth() + offset($)); // 👈 added token
return date;
});
const month = computed(($) => months[date($).getMonth()]) // 👈 added token
// ...
} (note that the The The On the other hand, it might feel good to inject everything, just for consistency - but, one could argue, this might actually make things harder to understand, as it raises the question of why they're injected, and there wouldn't be a very good answer besides "feels right". So I would lean towards free-standing functions if they are in fact dependency free. As to naming, I have no strong feelings. Name it however you want. But there are tangible benefits to mimicking the existing ecosystem, in terms of familiarity and adoption - Solid is already well established, and other projects are already copying that nomenclature. So I would worry less about names being "technically correct" and lean more towards familiarity and consistency with the ecosystem. Path of least surprise. Regarding effects, I would pull up another example from the date-picker: export const DateInput = ({ value, /* ... */ }) => {
const isOpen = observable(false);
// ...
subscribe(() => {
value(); // 👈 this looks odd
isOpen(false);
})
// ...
} (again, the This might answer one of your questions, in that this happens to demonstrate and effect being triggered by a change to Again, the difference I'd be interested in is the explicit subscription: export const DateInput = ({ value, /* ... */ }, { observable, subscribe }) => {
const isOpen = observable(false);
// ...
subscribe(($) => {
value($); // 👈 explicit subscription
isOpen(false);
})
// ...
} I think it's already obvious why this is better - the free standing call to For me, this is the motivation, and why I was so interested in Haptic. 🙂 Everything else is kind of secondary and (in my opinion) not where the important differences are - so in every other respect, mainly features and terminology, I would lean towards resembling Sinuous or Solid as much as possible. People like Solid - a few of us don't like the magic, and that's what we're trying to fix, right? I would start with something that deviates from existing libraries mainly on that point. I'd like to see the key problem solved first - questioning other details could come later, after proving that the important change is worth while. By the way, my date picker example has been ported between many frameworks over the years - it's designed to demonstrate components and essential state management features, composition, modularity, and reuse. I've ported it to basically every framework I've ever tried, probably dozens. I've found this makes a better benchmark and answers more questions than a counter or a to-do list, both of which are more "hello world" and less "things people actually need". 😅 It doesn't look like this is all the way there yet, but I would be happy to try porting it again, at your say-so. I can't really offer to help much with the library itself, beyond discussing things, but I'd be glad to help you push the framework and see how it holds up when you think it's ready. 😁 |
hey @mindplay-dk thank you very much for the response. And sorry for the late reply - I have been busy with some other stuff.
Yeah thanks a lot for your feedback. It's really useful since it helps me change the api surface based on developer experience feedback. I have implemented 2) and 3) from my list(.run on wire, and previousValue). For 1) I started on it and have in the meantime have added a computedSignal function(exposed in component as alfama/src/core/state/signal.ts Lines 44 to 52 in 7a90620
This is just a stopgap since it was fairly easy to implement. I still have to look into subscription for wires, and will get to it hopefully next week. Btw, your date picker example is very good! I didn't finish, but started porting it to alfama as well. I didn't finish, but I realised that to render the row it needs to the use stores instead of signals, since only stores could use the |
You don't need ${() => weeks().map(week => html`
<tr>
${week.map(day => html`
<td class="date-picker-btn ${day.class}" onClick=${() => { offset(0); value(day.value) }}>${day.date}</td>
`)}
</tr>
`)} it uses regular JS array |
I can't find a way to wire a wire. (computed signal derived from a computed signal.)
I'm not sure if this is supported or not - I don't see a real example in
examples/kitchen-sink
, and the documentation in the README doesn't seem to cover it.I'm confused as to the intended use of the
$
token provided towire
functions - in some cases, the token is passed to a signal to subscribe:that's the "textbook" example from the README, which does work.
but I would expect I'd be able to subscribe to computed signals just the same:
which doesn't work, and the computed signal doesn't accept any arguments.
I don't see a basic example of subscribing to a computed signal in
examples/kitch-sink
, but I did see subscriptions being created to what I presume are computed signals from some of the higher order functions, which seem to use this pattern:this doesn't work in my simple example either though.
and if that is the intended usage, I think that's problematic. 🤔
I would expect signals and derived signals to be as consistent as possible - having to pass the
$
token in some cases, and call it in others, would get really confusing really fast, and will almost definitely create problems when refactoring between regular and computed signals.(the terminology is a bit confusing as well, and I wonder if we could align better with Solid here, on both counts - usage as well as naming.)
I'm sure there's an explanation, but, arriving with some familiarity with Solid and Sinuous, and many other frameworks, I gave up after about an hour of "trying stuff", so there is at least a documentation problem here.
I want to port all my usual demos, which I've been porting between frameworks for many years - at least the ones you've seen in the Sinuous README ought to be portable, but this feels like maybe I'm a bit early? 😅
The text was updated successfully, but these errors were encountered: