Wscats/react-tutorial

React实现双向数据绑定

Wscats opened this issue · 0 comments

利用Proxy对数据进行劫持,自动触发this.setState

import { define, WeElement, html, h, extend, get, set } from "omi";

export interface appOptions {
    name: string;
    view(props?: any, state?: any, ref?: any);
    state?: any;
    propTypes?: any;
    props?: any;
    defaultProps?: any;
    css?: string;
    install?(props?: any, state?: any, ref?: any);
    installed?(props?: any, state?: any, ref?: any);
    uninstall?(props?: any, state?: any, ref?: any);
    beforeUpdate?(props?: any, state?: any, ref?: any);
    updated?(props?: any, state?: any, ref?: any);
    beforeRender?(props?: any, state?: any, ref?: any);
    receiveProps?(props?: any, state?: any, ref?: any);
}

// Added code
const isObject = obj => Object.prototype.toString.call(obj) === '[object Object]';
// Added code
const observify = (obj, that) => {
    if (!isObject(obj)) {
        return obj;
    }
    Object.keys(obj).forEach(key => {
        obj[key] = observify(obj[key], that);
    });

    return Observer(obj, that);
}
// Added code
const Observer = (obj, that) => {
    return new Proxy(obj, {
        set(obj, prop, value) {
            const res = Reflect.set(obj, prop, value);
            that.update();
            return res;
        }
    });
}

const app = ({
    name,
    view,
    state,
    propTypes,
    props,
    defaultProps,
    css,
    install,
    installed,
    uninstall,
    beforeUpdate,
    updated,
    beforeRender,
    receiveProps
}: appOptions) => {
    define(name, class extends WeElement {
        state = Object.assign({}, state);

        static props = props;
        static propTypes = propTypes;
        static defaultProps = defaultProps;
        static css = css;
        private ref;

        constructor() {
            super();
            (that => {
                // Added code
                that.state = observify(that.state, that)
            })(this);
        }

        install() {
            install &&
                install(
                    this.props ? this.props : {},
                    this.state ? this.state : {},
                    this
                );
        }

        installed() {
            installed &&
                installed(
                    this.props ? this.props : {},
                    this.state ? this.state : {},
                    this
                );
        }

        uninstall() {
            uninstall &&
                uninstall(
                    this.props ? this.props : {},
                    this.state ? this.state : {},
                    this
                );
        }

        render(oProps, oState) {
            return view(
                this.props ? this.props : oProps,
                this.state ? this.state : oState,
                this
            );
        }
    });
};

extend("model", (el: any, path, scope) => {
    el.value = get(scope, path);
    el.addEventListener("input", () => {
        set(scope, path, el.value);
        scope.update();
    });
});

export { html, h, app };