I am trying to understand how Facebook Flux works by looking at the source code of their flux chat example.
There, I saw this code:
var MessageStore = assign({}, EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
},
/**
* #param {function} callback
*/
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
...
}
...
module.exports = MessageStore;
...where assign is just polyfilled Object.assign from ES6 spec.
Hm. Would this code, using classes and extends instead, work? Would it mean the same thing? What are differences and advantages/disadvantages of this approach?
class MessageStore extends EventEmitter {
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
...
}
module.exports = new MessageStore();
I am asking, because, coming from other languages, I intuitively understand class/extends, while prototype-based inheritance is always a little unclear to me.
Here is working code that you can use with regards to ES6 syntax and your situation:
import EventEmitter from 'events';
const CHANGE_EVENT = 'change';
class MessageStore extends EventEmitter {
constructor() {
super();
}
addChangeListener = (callback) => {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener = (callback) => {
this.removeListener(CHANGE_EVENT, callback);
}
emitChange = () => {
this.emit(CHANGE_EVENT);
}
}
Note, I prefer the ES6 function literal syntax because it ensures that "this" is always bound to the enclosing object context.
For a fully working ES6 store example, please feel free to review the stores code in my Babel React Starter App
This is also a useful reference on ES6 classes that visually explains what is going on inside the body of a class definition.
class extends:*
You are extending a generic class, which is sometimes exactly what you want, e.g. a button extends a domElement, but a button should not extend an EventEmitter because they have nothing in common.
Object.assign:
With Object.assign you are "mixin" a new functionality into the target object, e.g. a Store may mixin an EventEmitter. In Java you would use Store implements EventEmitter which is a bit more self explaining.
Related
I'm a bit new to React and I'm currently developing a Proyect which has a service layer. To do so, I created a function component which would have the methods as variables:
const CustomComponent = () => {
method1 = () => {...},
method2 = () => {...},
method3 = () => {...}
}
export default CustomComponent;
This component would then be imported to the component that will use it.
To make my architecture as clean as possible, I wanted to make some of the methods private. However, as you may already know, that is not possible to do in the solution I proposed. Do hoy have an idea on how to achieve this, or maybe there is a convention to make a service layer I'm not aware of?
Thank you so much in advance!
The architecture which I find particularly clean and maintainable is one where you split off logic from presentation into two files like this:
Service layer (ts):
export class Service implements ServiceInterface {
constructor(private instanceVariable: string = "foo") { }
private methodOne(): string {
return this.instanceVariable
}
public methodTwo(argumentVariable: string): string {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
interface ServiceInterface {
methodTwo(argumentVariable: string): string;
}
export default new Service();
Service layer (js):
export class Service {
instanceVariable;
constructor(contructorArgument) {
this.instanceVariable = contructorArgument;
}
methodOne() {
return this.instanceVariable
}
methodTwo(argumentVariable) {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
export default new Service();
Presentation layer:
import Service from "./service.ts";
const FunctionalComponent = () => {
const [localState, setLocalState] = useState(localStateInit);
return (
<>
<div>{Service.methodTwo("bar")}</div>
</>
)
}
Few things happen here (mostly regarding ts implementation).
Keep component's service and presentation layers in separate files.
Use an interface to describe the service class and its methods. This will help to work with your service layer in your component as you'll get Typescript's IntelliSense.
For this example I'm exporting an instance of the service as default export from its file. This gives you a cleaner API in your component's file, where you can call methods without having to "pollute" component file with instance creation. This has at least the following two drawbacks:
you mostly lose ability to work nicely with static class members
preconfigured instance variable (initiated as a private member in constructor) means its value cannot be replaced in testing.
If any of above are a no go, then clean up the constructor, export just the class itself and instantiate it as required in component file.
I'm also exporting the class itself. This is for testing purposes. In testing you want to be able to swap out arguments passed into class' constructor and you need to have class definition to do that.
You'll notice the shorthand notation for declaring and instantiating a private class variable in the constructor: private instanceVariable: string = "foo". This is equivalent to something like this:
class Service {
private instanceVariable: string;
constructor(constructorArgument: string) {
this.instanceVariable = constructorArgument;
}
Such notation is particularly nice when used with dependency injection.
Overall, this setup will help you with unit testing logic in your service layer, as you can test it like any other class. This comes particularly handy when there's a lot of conditional rendering logic.
Let me know if this is what you've been looking for. Maybe we could tailor it better for your use case.
I am learning how to use decorators in Javascript and am confused as to when its appropriate to use class inheritance vs decorators?
For instance the following uses decorators to add a method to a class. It also overwrites one of the decorated classes methods.
import $ from "jquery";
function write(msg) {
$("#app").prepend(msg);
}
function clean(constructor) {
return class extends constructor {
foo() {
write("<h1>from the Decorated class</h1>");
}
bar() {
write("I haz bar");
}
};
}
#clean
class Hello {
foo() {
write("<h1>from the undecorated class</h1>");
}
}
const h = new Hello();
h.();
AFAIK, with inheritance — if the parent and child classes have the same methods, it would be flipped: child would overwrite the parent. In a situation where I would NOT want this to happen, decorators would be the desired choice. Is that correct?
P.S.
I know decorators not officially in the language yet.
I have a general paradigm from which I'd like to create objects. Currently, I have it written in such a way that the parent class builds the paradigm from a configuration object given to it by the subclass. The configuration object defines all of the class' characteristics, and the class is also able to overload any methods that need to be slightly different from one implementation of the paradigm to the next.
This approach is convenient as it allows me to:
avoid a long list of parameters for the constructor,
prevent the subclass from needing to define the attributes in any particular order, and
prevent the subclass from needing to explicitly create instances that the parent constructor can imply from the configuration.
As much as I liked the cleanliness and flexibility of sending this configuration object to super(), I've found a glaring limitation to this approach:
I cannot make a reference to this until super has completed.
class Paradigm {
constructor(config) {
this.name = config.name;
this.relationships = config.relationships;
}
}
class Instance extends Paradigm {
constructor(name) {
super({
name: name,
relationships: {
children: {
foo: new Foo(this) // Error: `this` referenced before `super`
}
}
});
}
}
class Foo {
constructor(parent) {
this.parent = parent;
}
}
NOTE: The configuration object is typically significantly larger than this, which is why I'm using it at all.
I can imagine there are many ways to approach this, but I'm most interested in what would be the correct way.
Should I be using functions in place of statements that require a reference to this and only execute them when they are needed?
Should I keep the same approach, but simply replace super({...}) with this.build({...})?
Should I abandon the idea of the configuration object altogether and instead take a different approach?
The fact that this is needed before super often suggests that a constructor contains logic that should be moved to separate method.
In some cases some workarounds are possible, as long as they don't cause problems. E.g., a part of configuration that requires this can be instantiated later:
constructor(name) {
const config = {
name: name,
relationships: {
children: {};
}
};
super(config);
config.relationships.children.foo = new Foo(this);
}
Of course, this presumes that relationships is just stored as a reference and isn't processed on construction.
In more severe cases class hierarchy (Instance and Paradigm) may be required to be converted to ES5 classes, since ES6 classes can extend regular functions but not vice versa.
A possible way would be to change your Paradigma to this:
class Paradigm {
constructor(config) {
Object.assign(this, config(this));
}
}
So that you can do:
class Instance extends Paradigm {
constructor(name) {
super((context) => ({
name: name,
relationships: {
children: {
foo: new Foo(context)
}
}
}));
}
}
But actually this is a bad way of solving it...
Another way could be to do it the other way round:
const Paradigma = cls => class Paradigma extends cls {
constructor(...args){
super(config => setTimeout(() => Object.assign(this, config), 1), ...args);
}
};
So you can do:
const Instance = Paradigma(class {
constructor(build, name){
build({name});
}
});
new Instance("Test");
While I'm not huge into forcing OOP into a functional language, I'm struggling to understand what a peer of mine did to export modules from a Class. All I'm looking for is what to call this so I can continue to do research. From what I understand they were including some external SDK to be passed into an internal class which would inherit everything into the LibIncludes. This is suppose to allow all of the classes to inherit into the LibIncludes and LibIncludes inherits from Object. What I'm running into now is that anytime I try to call LibIncludes.Handlers; and execute a function included in Handlers I'm getting undefined. I can't figure out what pattern he applied to make this work and everything in ES6 shows an entirely different approach to exporting and importing between classes for inheritance. Any help would be greatly appreciated.
// index.js
const ExternalSdk = new SDK.Function();
const HandlerService = require('./hander/handler.js');
class LibIncludes {
static compose() {
const Handler = new HandlerSvc(ExternalSdk);
return {
Handler
};
}
}
module.exports = LibIncludes;
let function = LibIncludes.sdkFunciton;
// function should be invoked and return some object
Here's the solution I came up with for refactoring. It seems cleaner and without the static members:
// index.js
const ExternalSdk = new SDK.Function();
const HandlerService = require('./hander/handler.js');
module.exports = class LibIncludes {
constructor(handler) {
this.handler = new HandlerSvc(ExternalSdk);
}
}
// app.js
const lib = require('./index');
var getSomething = new lib();
console.log(getSomething.handler);
// function should be invoked and return some object
I'm trying to get my head around the scope of functions. _internalFunction works well, but how do I call _externalFunction instead?
I've tried self=this and then this._externalFunction inside _renderRow and also tried () => {this._externalFunction} but it didn't work.
class sandbox extends Component {
//some code removed for clarity
_renderRow(item) {
const _internalFunction = () => {
Alert.alert('Internal');
};
return (<Text onPress={_internalFunction}>{item}</Text>);
}
_externalFunction() {
Alert.alert('External');
};
}
Here's the code in React Native Playground to fiddle with:
https://rnplay.org/apps/5CIGvA
Thanks in advance! :)
In ES6 you need to manually bind this to the instance. Here is a quote from React documentation:
In React components declared as ES6 classes, methods follow the same
semantics as regular ES6 classes. This means that they don't
automatically bind this to the instance. You'll have to explicitly
use .bind(this) in the constructor:
Therefore you need to bind your function in constructor:
constructor() {
super();
this._externalFunction = this._externalFunction.bind(this);
}
And then you can use this._externalFunction in your component:
_renderRow(item) {
return (<Text onPress={this._externalFunction}>{item}</Text>);
}