asci/lokka-hoc

View on GitHub
src/lokkifyFactory.js

Summary

Maintainability
B
6 hrs
Test Coverage
module.exports = function lokkifyFactory(lokkaClient, viewFramework) {

  if (!viewFramework && typeof window !== undefined) {
    viewFramework = window.React || window.preact;

    if (!viewFramework) {
      throw new Error('No suitable view layer found in window (expect to have: React or preact)');
    }
  }

  const jsxRenderer = viewFramework.createElement || viewFramework.h;
  if (!jsxRenderer) {
    throw new Error('No suitable jsx function provided (expect to have: React or preact)');
  }

  function fetcher(query, vars) {
    return lokkaClient.query(query, vars);
  }

  function lokkify(ChildComponent, query, mutations = {}) {
    let queryFunc = query;
    if (typeof query === 'string') {
      queryFunc = () => query;
    }

    return class LokkaHighOrderComponent extends viewFramework.Component {
      constructor(...args) {
        super(...args);
        this.state = {
          loading: true,
          mutate(name, vars) {
            return mutations[name] && lokkaClient.mutate(mutations[name], vars);
          }
        };
      }

      componentWillReceiveProps(nextProps) {
        setTimeout(() => this._refetch(nextProps));
      }

      componentWillUnmount() {
        this.mounted = false;
      }

      componentDidMount() {
        this.mounted = true;
        this.queryId = 0;
        const refetch = (vars) => {
          const queryId = ++this.queryId;
          this.mounted && fetcher(queryFunc(this.props), vars || this.props).then((data) => {
            this.mounted && queryId === this.queryId && this.setState({
              loading: false,
              refetch,
              errors: null,
              data
            });
          }, (errors) => {
            this.mounted && queryId === this.queryId && this.setState({
              loading: false,
              refetch,
              data: null,
              errors: [errors]
            });
          });
          this.setState({
            loading: true
          });
        };
        this._refetch = refetch;

        refetch();
      }

      render() {
        return jsxRenderer(
          ChildComponent,
          {...this.state, ...this.props},
          ...(this.props.children || [])
        );
      }
    };
  }

  return lokkify;
};