Skip to content
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

New feature: Async route support #708

Open
vgel opened this issue Mar 2, 2020 · 1 comment
Open

New feature: Async route support #708

vgel opened this issue Mar 2, 2020 · 1 comment

Comments

@vgel
Copy link

vgel commented Mar 2, 2020

Hi,
Really liking Choo so far! One thing I was missing was the ability to define an async route (I'm working on a game and wanted to preload assets). I didn't see a simple way to accomplish this (maybe I missed something obvious), so I wrote a little module that augments app with an asyncRoute method:

const app = withAsyncRoute(choo());

app.asyncRoute('/', loadResources,
    () => html`<div id="root"><h1>Loading...</h1></div>`, 
    (state, emit, data) => html`<div id="root">Loaded ${data}</div>`
    (state, emit, err, params) => {
        console.error('error loading /:', params, err, state);
        return html`
            <div id="root">
                <h1 style="color: red">Error loading / (see console)</h1>
            </div>
        `;
    },
);

Was wondering if there's interest in either merging this function into Choo proper, or as a third-party npm module?

For reference, here's the module -- it's pretty simple:

module.exports = (app) => Object.assign(app, {
    /**
     * @param  {string} route
     * @param  {Promise<Data>|Function<Promise<Data>>}       promise
     * @param  {Function<State, Emitter, RouteParams>}       loadingHandler
     * @param  {Function<State, Emitter, Data, RouteParams>} loadedHandler
     * @param  {Function<State, Emitter, *, RouteParams>}    errorHandler
     */
    asyncRoute: (route, promise, loadingHandler, loadedHandler, errorHandler) => {
        app.use((state, emitter) => {
            const emit = emitter.emit.bind(emitter);

            app.router.on(route, (params) => {
                state.params = params;

                if (typeof promise === 'function') {
                    promise = promise();
                }

                let completed = false;
                let isError = false;
                let data = null;

                promise.then(result => {
                    completed = true;
                    data = result;
                    emitter.emit('render');
                }).catch(err => {
                    completed = isError = true;
                    data = err;
                    emitter.emit('render');
                });

                return () => {
                    if (!completed) {
                        return loadingHandler(state, emit, params);
                    } else if (isError) {
                        return errorHandler(state, emit, data, params);
                    } else {
                        return loadedHandler(state, emit, data, params);
                    }
                };
            });
        });
    }
});
@blahah
Copy link
Contributor

blahah commented Jun 23, 2020

Related: async event messaging for choo. Beware: here be dragons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants