-
Notifications
You must be signed in to change notification settings - Fork 781
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
[RFC] What if hyperapp was just a bit less magical and a bit more transparent? #380
Comments
@jorgebucaran is the outer |
@okwolf You are right, it's not needed in this case because we don't use the state to call setTimeout! 🎉 document.body.appendChild(
render(state => (
<main>
<h1>{state.count}</h1>
<button onclick={() => update(state => ({ count: state.count + 1 }))}>
+
</button>
<button
onclick={() =>
setTimeout(() => {
update(state => ({ count: state.count - 1 }))
}, 1000)}
>
-
</button>
</main>
))
) ...but if we need to access, e.g., <button
onclick={() =>
update(({ delay }) => {
setTimeout(() => {
update(state => ({ count: state.count - 1 }))
}, delay)
})}
/> |
BTW I called the functions |
I think it would be worth exploring, and I'd like to experiment with it. Perhaps we could create a branch for it? Publish it as hyperapp2000 or something. It's hard to say yay or nay off hand without exploring it a bit in code. I'm thinking about some of the patterns I depend on (wether kosher or not), such as custom-events for separating concerns, scoped updates, and prewired components. They'll probably look a lot different if they're even relevant under this new paradigm. One thing I like about the current paradigm, is that the mixins and events system gives you one central place to customize a lot of things. If we don't have a render event in the new paradigm, for instance you can't inject other stuff to the view as arguments (if that's what you want). Not via a mixin anyway. You'd have to wrap the render function. |
It would feel awesome. Wondering what impact this would have on the router and other components that currently rely on mixins. |
Like @zaceno, I currently rely on the event system in an app I'm developing. Not saying similar things couldn't be accomplished with the new API, but I'd be curious to see a realistic application before/after. Something with routing and data fetching that uses the existing events system. Even just an implentation of the router and logger would be useful to see how it could work. I can see the benefit of decoupling actions from the app initialization. You're basically changing hyperapp from using dependency injection to requiring devs to manually import whatever actions they're going to use in the file. That probably will make type checking, editor autocomplete and dead code elimination easier. The current version of hyperapp has made me 100x more productive than I was with other frameworks, so I reserve my right to resist change very strongly. 😁 |
Wow. Conceptually it looks awesome to me. I don't know exactly what would be the practical implications and if the developer experience would be better or not. But this seems to summarize the essence of the functional UI paradigm, and the flexibility it exhibits is amazing. Please release it in any way so we can play with it. And by the way, I'm following you "behind the trenches" and I'm impressed by the community work you all are doing: making all the evolution of the library transparent, and involving all the people. Congrats 👏 👏 |
I dont know if I am a little bit off topic, but here we go. I personnaly think all the magical about Hyperapp is about actions. And more precisely about the actions I need to define and the actions I will use all other the framework. app({
actions: {
add(state, actions, { value }) {
return { count: state.count + value }
}
},
view(state, actions) {
return <button onclick={() => actions.add({ value: 3 })}/>
}
}) I have to define Now we admitted all over HA to define all functiont that way (state, actions, data) => result I think this is really a great thing to have only one function signature all over the framework. This will add simplicity and cut some questions. But what about thinking all entries of the framework as High Order Functions ? All the entries/hooks of the framework will now follow only one function signature. (state, actions) => (data) => function So it could be also a great standar to introduce thunk for all the async stuff instead of Promise. (state, actions) => (data) => (thunk) => function So I guess it will be more easy to understand what I define and what I get. app({
actions: {
add(state, actions) {
return ({ value }) => { count: state.count + value }
}
},
view(state, actions) {
return <button onclick={() => actions.add({ value: 3 })}/>
}
}) A more complete example (with sync and async) could be, the following counter. app({
state: {
count: 0
},
view: (state, actions) =>
<main>
<h1>
{state.count}
</h1>
<button onclick={() => actions.subLater(1, 3000)} disabled={state.count <= 0}>ー (3 sec)</button>
<button onclick={() => actions.sub(1)} disabled={state.count <= 0}>ー (now)</button>
<button onclick={() => actions.add(1)}>+ (now)</button>
<button onclick={() => actions.addLater(1, 3000)}>+ (3 sec)</button>
</main>,
actions: {
sub: (state, actions) => (value) => ({ count: state.count - value }),
add: (state, actions) => (value) => ({ count: state.count + value }),
subLater: (state, actions) => (value, time) => update => {
setTimeout(() => {
update(state => state.count <= 0 ? {} : { count: state.count - value })
}, time)
},
addLater: (state, actions) => (value, time) => update => {
setTimeout(() => {
update(state => ({ count: state.count + value }))
}, time)
}
}
}) |
In your proposal you introduce a function Implementation details aside, this means you could do this: state: {
count: 0,
},
actions: {
resetCount: _ => ({ count: 0 }),
setCountTo: data => _ => ({ count: data }),
addToCount: data => state => ({ count: state.count + data }),
},
view: state =>
h('button', {
oncreate: e => setInterval(_ => call(actions.addToCount(1)), 1000),
onclick: e => call(actions.resetCount),
}, state.count) There are pros and cons to this.. have a think about it. I'm happy to answer questions 😅 |
If you are talking about the |
It is like the addToCount: (state, actions, data) => update => update(state => ({ count: state.count + data })), |
Thank you everyone for your invaluable feedback. I'll be closing here and updating #385 where I'll explain the exciting upcoming changes to Hyperapp. 👋❤️ |
This is not a proposal to rewrite hyperapp, but just an attempt to gather some feedback from the community about our API.
If this were to happen it would be a major breaking change. This would be so major that one might as well publish it as a different "framework". 😉
I'd just like to share the API I thought up with all of you so help me decide if this could ever be for us or if I should explore this idea elsewhere. 🤔
Here it comes...
Please give it 5 minutes and think about all the implications. See how by decoupling
render
andupdate
from the app call that means we no longer need actions or events. And mixins, well those can be implemented in a manner similar to Redux enhancers, as the second argument to theapp()
call.On the other hand you are responsible for initializing the app yourself and merging the state, actions and other stuff exported by mixins or component-like mixins.
I am not in favor or replacing the current API for this (yet), but I am starting to like it a lot. Like @lukejacksonn said, food for thought. 🍝
EDIT: Corrected as pointed out by @okwolf.
The text was updated successfully, but these errors were encountered: