I am trying to create a mixin for a Polymer 2.0 components (class based syntax) with something like below. Is there a way to pass the options to the class the way I am doing it right now?
Polymer element definition with the mixin:
class PodcastListView extends PolymerApolloBehavior(Polymer.Element, myOptions) {
//some code
}
The mixin class:
export const PolymerApolloBehavior = (superclass, options) => class extends superclass {
constructor() {
console.log(options);
}
}
I can suggest you function-wrapper for your PodcastListView class that will makes a new one with new behavior. It will look something like this:
export const PolymerApolloBehavior = (original, options) => {
let result = Object.assign({}, original)
const originalConstructor = result.prototype.constructor
result.prototype.constructor = () => {
console.log(options) // your behavior
originalConstructor() // original constructor
}
// any changes of class
return result
}
And now you can apply your new behavior:
export default PolymerApolloBehavior(PodcastListView, {behaviorOptions})
Related
I have this situation but I don't know if it's ok to do something like this.
If I save an object inside the state of my component, can the object modify itself without using setState?
File A.js
export default class A {
constructor(value) {
this.value = value;
}
setValue(value) {
this.value = value;
}
}
File B_Component.js
import React from "react";
import A from "./A";
class B_Component extends React.Component {
constructor(props) {
super(props);
this.state = {
aObj = new A("foo")
}
}
bar = () => {
this.state.aObj.setValue("bar");
}
...render etc...
}
Basically this should modify the state of the component without using setState.
Is this correct or there may be problems?
Is this correct or there may be problems?
There may be problems. :-) If you're rendering that object's value, then you're breaking one of the fundamental rules of React, which is that you can't directly modify state. If you do, the component won't re-render.
Instead, you create a new object and save the new object in state:
bar = () => {
this.setState({aObj: new A("bar")});
}
Or if you want to reuse other aspects of the object and only change value:
bar = () => {
const aObj = new A(this.state.aObj); // Where this constructor copies all the
// relevant properties
aObj.setValue("bar");
this.setState({aObj});
}
The A constructor would be
constructor(other) {
this.value = other.value;
// ...repeat for any other properties...
}
Or you might give A a new function, withValue, that creates a new A instance with an updated value:
class A {
constructor(value) {
this.value = value;
// ...other stuff...
}
withValue(value) {
const a = new A(value);
// ...copy any other stuff to `a`...
return a;
}
}
Then:
bar = () => {
this.setState({aObj: this.state.aObj.withValue("bar")});
}
Say I have a generic class module:
export class MyCalc {
data = {}
...
}
And say I want to extend more functionality:
export class MyCalcLoader {
load = some_data => {
this.data = some_data;
}
}
export class MyCalcUI {
print = () => {
document.write(JSON.stringify(this.data));
}
}
What is the appropriate way to extend MyCalc and also use those extensions/plugins?
import {MyCalc} from "./MyCalc.js";
import {MyCalcLoader} from "./MyCalcLoader.js";
import {MyCalcUI} from "./MyCalcUI.js";
// TODO: MakeMyCalcExtendLoaderAndUi();
class BankingCalc extends MyCalc {
config = {...}
constructor() {
super();
}
}
const banking_calc = new BankingCalc();
banking_calc.load({...});
banking_calc.print();
I've thought through a few different janky ways to do this, but I'm sure this is common enough and that there's a right way to do it with vanilla ES6.
You could use Mixins:
export const MyCalcLoader = Super => class MyCalcLoader extends Super {
load = some_data => {
this.data = some_data;
}
}
export const MyCalcUI = Super => class MyCalcUI extends Super {
print = () => {
document.write(JSON.stringify(this.data));
}
}
Then compose the class as:
class BankingCalc extends MyCalcLoader(MyCalcUI(MyCalc)) {
//...
}
So I have come across an interesting issue while trying to extend a class to use in another class and then import it to another file.
'class-test.js':
export default class MyClass {
constructor () {
this.date_created = new Date()
this.posts = new Posts()
}
}
class Posts extends Array {
add (val) {
this.push(val)
}
}
Then when I create a new MyClass instance in another file (and import MyClass from class-test.js), the myClass.posts property is only being seen as an Array and so doesn't have the extended function add()
I think the problem is that the Posts class is not being moved with the MyClass class; but without casting I have no idea how to tell it to use that class.
Where I'm particularly frustrated is it works fine if all in one file:
class MyClass {
constructor () {
this.date_created = new Date()
this.posts = new Posts()
}
}
class Posts extends Array {
add (val) {
this.push(val)
}
}
var x = new MyClass('as', 'asd')
x.posts.add('asdf')
console.log(x.posts)
x.posts.add('qwer')
x.posts.add('zxcv')
console.log(x.posts)
Did you try to export, and import both classes ?
'class-def.js':
class MyClass {
constructor () {
this.date_created = new Date()
this.posts = new Posts()
}
}
class Posts extends Array {
add (val) {
this.push(val)
}
}
export { MyClass, Posts };
'class-test.js':
import { MyClass, Posts } from 'class-def.js';
var x = new MyClass('as', 'asd')
x.posts.add('asdf')
console.log(x.posts)
x.posts.add('qwer')
x.posts.add('zxcv')
console.log(x.posts)
I'm trying to create a base class, wrap that in a container, and then extending this within my other components.
Here is a simplified example:
let state = new State();
class Base extends React.Component<{}, {}> {
}
const Container = state.connect(
() => {
return {
}
},
() => {
return {
}
}
)(Base);
class S extends Container {
}
This, however, is returning an error:
`error TS2507: Type 'any' is not a constructor function type.`.
If I extend the Base directly, it works fine, but then how would I get access to the state and dispatch actions that I'd put into the container?
UPDATE
I created the following interface (omitting templates for simplicity)
interface IState {
connect: (
mapStateToProps: () => any,
mapDispatchToProps: () => any,
) => (component: typeof React.Component) => typeof React.Component
}
let state: IState = new State();
Now class extension does not throw any error. However, the original Base class is never called! Only the constructor of the Connect method is called.
The idea here is that I will have an abstract component and container (all the dispatch actions are on the container). And I can then extend this component from my other classes. However, since the container contains all the dispatch actions, then I need to extend the container, not the component.
I think you can reuse the value returned by state.connect().
let state = new State();
class Base extends React.Component<{}, {}> {
}
class S extends Base {
}
const containerFactory = state.connect(
() => {
return {}
},
() => {
return {}
}
);
const BaseContainer = containerFactory(Base);
const SContainer = containerFactory(S);
I am kind of struggling with inheritance in JavaScript. Let's say I have a following class:
class Parent {
constructor({ name, someOtherStuff } = {}) {
this.name = name;
this.someOtherStuff = someOtherStuff;
}
someMethod() {
// ...
}
}
and I would like to create a decorator that would allow me to do following:
#parent({
name: 'foo',
someOtherStuff: 'bar'
})
class MyClass extends Component {
myMethod() {
// ...
}
}
const instance = new MyClass();
// Those tests must pass
expect(instance.someMethod).toBeFunction();
expect(instance.name).toEqual('foo');
expect(instance.someOtherStuff).toEqual('bar');
expect(instance.myMethod).toBeFunction();
expect(instance instanceof Parent).toBe(true);
expect(instance instanceof MyClass).toBe(true);
Is there a way to create such decorator? I tried multiple solutions, but none of them really satisfies all the tests.
const parent = (...args) => (Target) => {
// Target corresponds to MyClass
const parent = new Parent(...args);
// ...
};
lodash is allowed.
Why use decorators? You can just extend parent class
class MyClass extends Parent {
constructor() {
super({name: 'foo', someOtherStuff: 'bar'});
}
}
You can use decorators to create a new class that inherits, apply some mixins, and go from there. JS classes don't have mutliple inheritance, so you can't do this directly, but you can combine the two manually or create a proxy that will do what you want.
I've been using wrapper classes for a decorator-based DI library by returning a class like so:
static wrapClass(target, {hook = noop} = {}) {
return class wrapper extends target {
static get wrappedClass() {
return target;
}
constructor(...args) {
super(...Injector.fromParams(args).getDependencies(wrapper).concat(args));
}
}
}
The decorator is really returning a new constructor with closure over the original, but that's enough for most purposes.