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.
*/