knowthen / fpjs

Companion repo for Functional Programming for Beginners with Javascript
https://courses.knowthen.com/courses/functional-programming-for-beginners-with-javascript
96 stars 74 forks source link

init function instead of initModel in the app function? #6

Open 8483 opened 5 years ago

8483 commented 5 years ago

I was wondering how you'd implement an init function instead of initModel. How would we make an HTTP request that populates the initial data?

Like this in Elm:

init : (Model, Cmd Msg)
init = (initModel, getData)

main : Program Never
main = App.program
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}

How would the Javascript look like? I can't wrap my head around it.

function app(initModel, update, view, node) {
            // The initial model is set as the current model.
            let model = initModel;
            // The new view is rendered based on the initial model.
            let currentView = view(dispatch, model);
            // The new view is created and appended to the DOM.
            let rootNode = createElement(currentView);
            node.appendChild(rootNode);

            // Dispatch sends a message with a type and payload.
            function dispatch(msg) {
                // Update "catches" it, updates the current model, and returns it.
                // returns either a model or an array with model and command
                const updates = update(msg, model);
                // Array check boolean
                const isArray = updates.constructor === Array;
                // Get the model from the array. If not array, it's just the model.
                model = isArray ? updates[0] : updates;
                // Get the command form the array
                const command = isArray ? updates[1] : null;
                // Pass the dispatch function and command object for HTTP execution
                httpEffects(dispatch, command);
                // Return the new view either from normal types, or HTTP ones
                // The new view is rendered based on the returned new model.
                const updatedView = view(dispatch, model);
                // The DOM updates are defined.
                const patches = diff(currentView, updatedView);
                // The DOM updates are applied.
                rootNode = patch(rootNode, patches);
                // The new view becomes the old view in for future dispatches.
                currentView = updatedView;
            }

            function httpEffects(dispatch, command) {
                if (command === null) {
                    return;
                }
                // Get the request object from the command.
                let request = command.request;
                // Fetch, and dispatch a success or fail message.
                fetch(request.url, request.headers, request.body)
                    .then(res => res.json())
                    .then(result => {
                        // Dispatch the returned message defined in the command.
                        dispatch(command.successMsg(result));
                    })
                    .catch(error => {
                        // Dispatch the returned message defined in the command.
                        dispatch(command.errorMsg(error));
                    });
            }
        }

        // App initializing.
        const rootNode = document.getElementById('app');
        app(initModel, update, view, rootNode);