Re: withReactSubviews.js

From disqus.com, 8 Months ago, written in JavaScript, viewed 3 times. This paste is a reply to withReactSubviews.js from disqus.com - go back
URL https://pastebin.freepbx.org/view/45197cdd/diff Embed
Viewing differences between withReactSubviews.js and Re: withReactSubviews.js
define('home/mixins/withReactSubviews',[
    'underscore',
], function (
    _
) {
    'use strict';

    // Shared modules, only need to be required once
    var React, ReactDOM;
    var sharedModules = {};  // path to imported module

    /**
     * Called once a module has been fetched. Saves the module
     * for future uses, stores it in the component for future
     * rendering, and calls any onFetch callbacks that have
     * been saved on this component.
     *
     * @param  {function} module - The fetched module
     * @param  {Object} component - The component for this view/module
     */
    var handleOnFetch = function (module, component) {
        sharedModules[component.path] = module;
        component.module = module;
        component.fetching = false;

        _.each(component.onFetch, function (fn) {
            if (fn)
                fn();
        });
    };

    /**
     * Called once a component has been rendered into the DOM
     * and we have a reference to it. Saves the ref for future
     * component prop updates and calls on onRef callbacks that
     * have been saved on this component.
     *
     * @param {ReactElement} ref - The ReactElement that has
     *                               been rendered into the DOM
     * @param  {Object} component - The component for this view/module
     */
    var handleRef = function (ref, component) {
        component.ref = ref;

        _.each(component.onRef, function (fn) {
            fn.call(component.ref);
        });
    };

    /**
     * Lazy fetches react modules and react libraries. Tries to use
     * previous imports if module has been imported before, and
     * prevents multiple fetches from kicking off at once.
     *
     * @param  {Object}   component - The component whose module to fetch
     * @param  {function} [callback] - A callback to call once the module
     *                                 has been fetched/retrieved
     */
    var loadModule = function (component, callback) {
        component.onFetch.push(callback);

        if (sharedModules[component.path]) {
            handleOnFetch(sharedModules[component.path], component);
            return;
        }

        if (component.fetching)
            return;

        component.fetching = true;

        // Require subview before react libraries because in production
        // the libraries are bundled into the subview file and are not
        // available to load until the subview file has been loaded.
        require([
            component.path,
        ], function (Module) {
            if (!React || !ReactDOM) {
                require([
                    'react',
                    'react-dom',
                ], function (
                    iReact,
                    iReactDOM
                ) {
                    React = iReact;
                    ReactDOM = iReactDOM;

                    handleOnFetch(Module, component);
                });
            } else {
                handleOnFetch(Module, component);
            }
        });
    };

    /**
     * Mixin takes in a list of react modules that may be rendered by this view.
     * Each module is specified by a path which will be used to reference it during
     * render or updating the props for that subview.
     *
     * Rendering a react subview will automatically import the subview module
     * and react libraries.
     *
     * @param  {string[]} modules - The list of module paths
     */
    var mixin = function (modules) {
        this.initialize = _.wrap(this.initialize, function (_initialize) {
            _initialize.apply(this, _.rest(arguments));

            // Since we map components by path, this view can only have 1
            // instance of a component as a subview. Can change the mapping
            // if need be.
            this._components = _.chain(modules)
                .map(function (path) {
                    return [path, {
                        path: path,
                        onFetch: [],
                        onRef: [],
                    }];
                })
                .object()
                .value();
        });

        /**
         * Renders the specified react component with the given props into
         * the given element. Fetches the module and react libraries if
         * necessary.
         *
         * @param  {string}   path - The path to fetch the module.
         * @param  {Object}   props - The initial props to pass to the
         *                            component.
         * @param  {DOMElement}   el - The element into which to render
         *                             the component.
         * @param  {function} [callback] - A function that will be called
         *                                 once the component exists in
         *                                 the DOM.
         */
        this.renderReactSubview = function (path, props, el, callback) {
            var component = this._components[path];
            if (!component)
                return;

            if (!component.module) {
                loadModule(component, _.bind(this.renderReactSubview, this, path, props, el, callback));
                return;
            }

            var ref = ReactDOM.render(
                React.createElement(React.createClass({
                    displayName: 'wrapper',
                    getInitialState: function () {
                        return props;
                    },
                    render: function () {
                        // Wrap component in an element with data-view-type=react. This is used to prevent
                        // the global backbone anchor click handler from reloading when the clicks come
                        // from a react page.
                        return React.createElement('div', { 'data-view-type': 'react' },
                            React.createElement(component.module, this.state)
                        );
                    },
                })),
                el,
                callback
            );

            handleRef(ref, component);
        };

        /**
         * Updates the set of props given to the component specified by the
         * given path. Expects the component to have been rendered via
         * renderReactSubview previously, even if the module fetching/
         * rendering is not yet complete.
         *
         * @param  {string} path - The path of the module which maps to a
         *                         previously rendered component.
         * @param  {Object} props - The new props to pass to the rendered
         *                          component
         */
        this.updateComponentProps = function (path, props) {
            var component = this._components[path];
            if (!component)
                return;

            if (!component.ref) {
                component.onRef.push(function () {
                    component.ref.setState(props);
                });
                return;
            }

            component.ref.setState(props);
        };
    };

    // Used only for testing
    mixin.forget = function () {
        sharedModules = {};
        React = undefined;
        ReactDOM = undefined;
    };

    return mixin;
});

// https://c.disquscdn.com/next/82c6de3/home/js/mixins/withReactSubviews.js

Replies to Re: withReactSubviews.js rss

Title Name Language When
publisher-admin/js/entry.js disqus.com javascript 8 Months ago.

Reply to "Re: withReactSubviews.js"

Here you can reply to the paste above