Last active
January 20, 2024 02:11
-
-
Save neurosnap/d552045dafcc8cc3bd6e3ab865701a17 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is an experimental view library that would compete with react, svelte, qwik.js, vue.js etc. | |
* | |
* Implementation reference: https://git.sr.ht/~erock/alpfx | |
* | |
* Features: | |
* - Instead of `view = func(state)` we have `view = func(event)` | |
* - This paradigm shift will: | |
* - make prop mgmt (e.g. when to update component) more manual | |
* - animations easier (events or transitions are sent to the component that the end-user | |
* can control) | |
* - Doesn't pretend to be declarative, there's no difference between how a component is | |
* rendered and what happens when user triggers event | |
* - They both function by responding to events | |
* - Components are pure functions -- no side-effects allowed | |
* - Components can return: | |
* - A command to perform IO | |
* - An array that represents HTML for a component | |
* - Both | |
* - `show` prop will conditionally render element | |
* - All state management for library and end-users are stored in a single global store (e.g. redux) | |
* - There is no local component state | |
* - Commands are generator functions that also do not contain side-effects but instead | |
* instruct the library runtime to perform IO side-effects. (ala redux-saga) | |
* - No JSX, just TS | |
* - With a global state mgmt system, we could add resumability on the server (ala qwik.js) | |
* - We could have a compilation step that figures out the different states a component could be in | |
* and then do manual DOM manipulations (ala svelte) | |
* - This would mean there's no virtual DOM | |
* - Async rendering, suspense, etc, is a bunch of overhead we then don't need to implement | |
*/ | |
import type { Store } from './types'; | |
interface MyState { | |
show: boolean; | |
movies: { id: string; title: string }[]; | |
movieProps: { title: string }; | |
} | |
const initMsg = () => ({ type: 'init', payload: null }); | |
// imaginary function that will emit events specific to a component | |
const emit = (type: string, ...args: any[]) => {}; | |
// imaginary function that will describe how an async function will by called by the runtime | |
const call = (...args: any[]) => {}; | |
function* cmdState<S extends Store = Store>(store: S, key: string, value: any) { | |
const next = { key, value }; | |
store.dispatch({ type: 'UPDATE_STATE', payload: next }); | |
} | |
function Toggle(store: Store<MyState>, msg = initMsg()) { | |
const { show = false } = store.getState(); | |
if (msg.type === 'click') { | |
return cmdState(store, 'show', !show); | |
} | |
return [ | |
'div', | |
[ | |
['button', { click: true }, show ? 'Collapse' : 'Expand'], | |
['div', { show }, 'This is some content'], | |
], | |
]; | |
} | |
function* cmdFetch(url: string) { | |
yield emit('loading'); | |
const resp = yield call(fetch, url); | |
if (!resp.ok) { | |
yield emit('error'); | |
} | |
const payload = yield call([resp, 'json']); | |
yield emit('success', payload); | |
} | |
function Movies(store: Store<MyState>, msg = initMsg()) { | |
switch (msg.type) { | |
case 'init': | |
return [cmdState(store, 'movieProps', msg.payload), cmdFetch('/movies')]; | |
case 'props': | |
// also have access to msg.payload.prev | |
return cmdState(store, 'movieProps', msg.payload.next); | |
case 'loading': | |
return ['div', 'loading']; | |
case 'error': | |
return ['div', `error: ${msg.payload}`]; | |
case 'success': | |
return [['div', 'success!'], cmdState(store, 'movies', msg.payload)]; | |
default: | |
const { movies = [], movieProps } = store.getState(); | |
return [ | |
'div', | |
[ | |
['div', movieProps.title], | |
movies.map((movie) => ['div', { key: movie.id }, movie.title]), | |
], | |
]; | |
} | |
} | |
export function App() { | |
return ['div', [[Toggle], ['hr'], [Movies, { title: 'nice' }]]]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment