colshacol
11/13/2017 - 5:21 PM

ContainerCreator

ContainerCreator

const methods = {
    getUpdatedUserProfile(store) {
        return (...args) => {
            store.props.actions.getUpdatedUserProfile(args.foo);
        };
    },
};

/*

  Methods are also explicitly passed the container (as "store"), which provides the same benefits
  as with getters. Each method (and getter) can be tested individually, providing more coverage,
  safety, and stability around our entire application.
  
  Taking advantage of closures, methods are invoked once upon instantiation of the container
  (this is when "store" is provided to them) and then return the function that will actually be
  used when invoked in the future.
 
  Furthermore, values can be created before the `return (...args) =>` and be used by the method
  in the future, only existing in that scope, never being public, and never being changed from
  outside that scope.

*/
const getters = {
    upperUserName(store) {
        return store.props.user.name.toUpperCase();
    },
};

/*

  Getters methods are attached to the container component and passed the
  container explicitly (as "store"). This makes testing 1,000,000 times easier,
  and it makes the code more transparent.
  
  Using this getter would simply be...
  
  this.upperUserName
  
  ... with no invocation needed, as it becomes an actual JavaScript getter.
  
  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters

*/
import React, { Component } from 'react';

import methods from './methods';
import getters from './getters';

class UserProfileContainer extends Container({ methods, getters }) {
    render() {
        return (
            <UserProfile
                userName={this.props.user.name}
                upperUserName={this.upperUserName}
                getUpdatedUserProfile={() => this.getUpdatedUserProfile({ foo: 'bar' })}
            />
        );
    }
}

/*

  The methods and getters are applied to UserProfileContainer and become available for use immediately.

*/
import React, { Component } from 'react';


const Container = ({ methods, getters }) => {
    return class extends Component {
        constructor(props) {
            super(props);

            const store = this;

            Object.entries(methods).forEach(([name, func]) => {
                store[name] = func(store);
            });

            Object.entries(getters).forEach(([name, func]) => {
                Object.defineProperty(store, name, {
                    get: function() {
                        return func(store);
                    },
                });
            });
        }
    };
};

/*

  This is a utility function that creates a class with getters and methods bound to it.
  (I mean to imply that we don't have to write this code in every container, haha.)

  It is very simple and provides the ability to be more modular with class methods and getters
  by allowing us to import our methods and getters from other files instead of them having to
  live directly on the component we create.

*/