Vue3 / How to pass data from mixin setup() to component - vue.js

I would like to pass my object based on JavaScript class from mixin to component without reactivity. I use TypeScript, so I can't set the object to this of mixin without setting types in data(). But data() reactivity breaks some thing in my object.
mixin.js:
export default {
setup() {
const foo = new Foo()
return {
foo,
}
}
}
component.js:
import mixin from './mixin.js'
export default {
setup() {
// How can I get foo here?
}
}
Update 1
Yes, it is good solution for using only one foo instance for everywhere.
But how can I use different foo instances for each component?
Same as in JS classes:
class Mixin {
foo() {
// ...
}
}
class Component extends Mixin {
bar() {
this.foo()
}
}

mixin.js
export const foo = new Foo()
Import (and use) foo anywhere in your app, including any setup() function:
import { foo } from './path/to/mixin'
The above uses the same instance everywhere. If you want to use different instances of foo in each separate component, mixin.js:
export const useFoo = () => new Foo()
Anywhere else:
import { useFoo } from './path/to/mixin'
const foo = useFoo()
However, take note the second approach creates a new intance of Foo() every time useFoo() is called. So once you called it, you must use foo in that component.
Calling useFoo() multiple times in the same component will generate multiple instances, unlike how you'd use useStore(), for example.
But, I'm wondering, why do you need a mixin in the first place? Why not use:
const foo = new Foo()
...in the components where you need it?
What are you trying to achieve? And, more importantly, why?

Related

React native setState on new Object

I have a class Two with a bunch of functions inside. Some of them are using this.setState({}) and they throw me a warning: setState(...): Can only update a mounted or mounting component.
Here's an example of the code:
class One extends React.Component {
constructor() {
super()
this.two = new Two;
}
componentDidMount() {
this.two.hello()
}
render() {
return (<View><Text>Hello World!</Text></View>)
}
}
class Two extends React.Component {
constructor() {
super()
this.state = {
connected: false
}
}
hello() {
this.setState({connected: true}) //This one throw the warning
}
}
Is there any way to do things in a better way? Since my class Two is functionnal, I would like to not change the code too much to have things working. Btw, I need to the this.two = new Two line.
Should I create a library, a module, or whatever? If so, can you give me a good tutorial?
If you are not mounting the Component, React can’t update it’s state using it’s built-in state handler.
And since you are not mounting it, it should probably not be a react component at all. Try using a regular class instead:
class Two {
constructor() {
super()
this.state = {
connected: false
}
}
hello() {
this.state.connected = true
}
}
The main problem here is you are trying to make components in React communicate in an unconventional way.
The way you want to go about this is to make use of props. This is how components talk to each other in React, instead of being direct, like you're attempting.
Check out my code here where I'm doing the same as you
Basically, I've written 2 examples in 1 here. The first is passing just raw data through to another component. (this.props.data.someData). And the second, which is more like what you're wanting to do, is using React's Life Cycle methods, to listen for when a function should run, through prop activation.
What this means in my example, is when the runFunction prop is passed into Two, either when it's first created componentDidMount() or when set to true later componentWillRecieveProps(), it will run the testFunction()

Aurelia- Inject into function

In my Aurelia SPA I have some functions I want to use in different modules. It relys on parameters given when called and parameters of a singleton. Is there a way to create an export function that I can inject my Auth singleton into without having to pass it as a parameter everytime I call the function?
A simple example of how I'd like it to look would be this.
import Auth from './auth/storage';
import { inject } from 'aurelia-framework';
#inject(Auth)
export function A(foo: boolean): boolean {
let auth = Auth;
if (auth.authorized && foo) {
return true
}
else {
return false
}
}
I know I could just wrap it in a class and use that but want to know if there is any way to achieve it similar to this
If you want to use dependency injection in a function, use Container from aurelia-dependency-injection:
import Auth from './auth/storage';
import { Container } from 'aurelia-dependency-injection';
export function A(foo: boolean): boolean {
let auth = Container.instance.get(Auth);
if (auth.authorized && foo) {
return true
}
else {
return false
}
}

Statically importing Kotlin Companion methods?

tl:dr; Is it possible to import a method inside a companion object of another class, without qualifying the import with Companion? That is, is there any possible way I can say import Bar.toFoo instead of import Bar.Companion.toFoo, assuming toFoo is a method on Bar's companion object?
We're migrating a class from Java to Kotlin. Our class looks like this:
class Bar {
static Foo toFoo() {
return new Foo();
}
}
And then, to use it, from a class that happens to be Kotlin, we say something like:
import Bar.toFoo;
// ...
Bar().convert(toFoo()); // like a Java 8 Collector
// ...
When we convert Bar to Kotlin, it looks like this:
class Bar {
companion object {
#JvmStatic fun toFoo() = Foo()
}
}
We'd like the calling code to work without modification, however
import Bar.toFoo
no longer works, even with #JvmStatic! Instead, we have to update it to
import Bar.Companion.toFoo
which we'd rather not have to do -- we want to switch the Bar class to Kotlin without updating the callers.
Thoughts? We're using Kotlin 1.1.2-2.
Unlike Java, Kotlin does not allow you to call static members via instance reference. Java dispatches these members based on the compile time declaration, so in
class Bar {
static Foo toFoo() { return new Foo(); }
}
class Foo extends Bar {
static Foo toFoo() { return new Foo(); }
}
class Baz {
void test() {
Bar fooAsBar = new Foo();
Foo foo = fooAsBar.toFoo();
}
}
In Java, fooAsBar.toFoo() will actually call Bar.toFoo() (the declared type) and not Foo.toFoo() (the runtime type). This is a source of misunderstanding and not good programming practice, so Kotlin does not support it.
However, you can define an extension function on Bar:
fun Bar?.toFoo() = Bar.toFoo()
Then you can call
val foo = fooAsBar.toFoo()

Specialized Singleton implementation

I am looking for specialized singleton implementation, probably I might be using wrong terminology and hence looking for expert suggestion. Here is my scenario:
There is common code which can be called by ComponentA or ComponentB. I need to push telemetry data from the common code. Telemetry needs to have information that whether this common code get called by ComponentA or ComponentB.
So common code will have just this line of code:
telemetry.pushData(this._area, data);
where this._area tells the telemetry data is getting pushed for which component
I need to push telemetry data from multiple places so it would be good if object got created once and used through out the code lifetime
One option I can think of passing component context to the common code which in mind doesn't look right, hence looking for suggestion what kind of pattern one should use in this case?
This is what I am thinking
// Telemetry.ts file present in shared code
export class Telemetry extends Singleton {
public constructor() {
super();
}
public static instance(): Telemetry {
return super.instance<Telemetry>(Telemetry);
}
public publishEvent(data): void {
if (!this.area) {
throw new Error("Error: Initialize telemetry class with right area");
}
pushtelemetryData(this.area, data);
}
public area: string;
}
// Create Telemetry object from component A
Telemetry.instance().area = "ComponentA";
// Shared code will call telemetry publishEvent
Telemetry.instance().publishEvent(data);
Thanks
It's not a good pattern to use in TypeScript where you would generally inject dependencies.
If you must absolutely do it then you can do it by faking it somewhat:
namespace Telemetry {
var instance : SingletonSomething;
export function push(data: Any) : void {
if (instance == null) {
instance = new SingletonSomething();
}
instance.push(data);
}
class SingletonSomething() { ... }
}
and then you could call
Telemetry.push(data);
You can imitate the singleton pattern in typescript easily:
class Telemetry {
private static instance: Telemetry;
public static getInstance(): Telemetry {
if (Telemetry.instance == null) {
Telemetry.instance = new Telemetry();
}
return Telemetry.instance;
}
...
}
If you have your code in some sort of closure (module, namespace, etc) then you can replace the static member with:
let telemetryInstance: Telemetry;
export class Telemetry {
public static getInstance(): Telemetry {
if (telemetryInstance == null) {
telemetryInstance = new Telemetry();
}
return telemetryInstance;
}
...
}
But then you can also replace the static method with:
let telemetryInstance: Telemetry;
export function getTelemetryInstance(): Telemetry {
if (telemetryInstance == null) {
telemetryInstance = new Telemetry();
}
return telemetryInstance;
}
export class Telemetry {
...
}
At this point, in case you are using some sort of closure, you might ask yourself if you really need the class at all?
If you use this as a module:
// telemetry.ts
export interface TelemetryData {
...
}
export function pushData(data: TelemetryData): void {
...
}
Then you get exactly what you're looking for, and this is more of the "javascript way" of doing it.
Edit
In the telemetry module there's no need to know the users of it.
If the Telemetry.pushData function needs to have information about the object that called it then define an interface for it:
// telemetry.ts
export interface TelemetryData {
...
}
export interface TelemetryComponent {
name: string;
...
}
export function pushData(data: TelemetryData, component: TelemetryComponent): void {
...
}
Then in the other modules, where you use it:
// someModule.ts
import * as Telemetry from "./telemetry";
class MyComponent implement Telemetry.TelemetryComponent {
// can also be a simple string property
public get name() {
return "MyComponent";
}
fn() {
...
Telemetry.pushData({ ... }, this);
}
}
2nd Edit
Because you are using a module system, your module files are enough to make singletons, there's no need for a class to achieve that.
You can do this:
// telemetry.ts
let area: string;
export interface TelemetryData {
...
}
export function setArea(usedArea: string) {
area = usedArea;
}
export function pushData(data: TelemetryData): void {
...
}
Then:
Telemetry.setArea("ComponentA");
...
Telemetry.publishEvent(data);
The telemetry module will be created only once per page, so you can treat the entire module as a singleton.
Export only the functions that are needed.

Can typescript external modules have circular dependencies?

It looks like this is not allowed. requireJS is throwing an error on the following (this post is different as it was resolved with internal modules):
element.ts:
import runProperties = require('./run-properties');
export class Element {
public static factory (element : IElement) : Element {
switch (element.type) {
case TYPE.RUN_PROPERTIES :
return new runProperties.RunProperties().deserialize(<runProperties.IRunProperties>element);
}
return null;
}
}
run-properties.ts:
import element = require('./element');
export class RunProperties extends element.Element implements IRunProperties {
}
No, modules can't have circular dependencies unless they are in the same file. Each file is being processed in sequence, synchronously, so the full file definition (including all of the exports for example) hasn't been completed when it goes to second file, which immediately tries to require/reference the first file, and so on.
Normally, you can break a circular dependency by introducing an interface or base class into a common definition file(s) (basically interfaces only) and having the other files use that as a common "interface" rather than directly referencing the classes. This is a typical pattern in many platforms.
I have same issue, I was able to fix it by creating factory class that allows registration of child classes and used Generics for instantiation.
Reference: https://www.typescriptlang.org/docs/handbook/generics.html#using-class-types-in-generics
See sample code below:
Base Class (abstract.control.ts)
export type AbstracControlOptions = {
key?:string;
}
export abstract class AbstractControl {
key:string;
constructor(options:AbstracControlOptions){
this.key = options.key;
}
}
Parent Class (container.ts)
import { AbstractControl, AbstracControlOptions } from './abstract.control';
import { Factory } from './factory';
export { AbstracControlOptions };
export abstract class Container extends AbstractControl {
children: AbstractControl[] = [];
constructor(options: AbstracControlOptions) {
super(options);
}
addChild(options: { type: string }) {
var Control:any = Factory.ControlMap[options.type];
if (Control) {
this.children.push(Factory.create(Control, options));
}
}
}
I don't have to import the child classes any more, because I'm using factory.ts to instantiate the child classes.
Factory Class(factory.ts)
import {AbstractControl, AbstracControlOptions} from './abstract.control';
type ControlMap<T extends AbstractControl> = {
[type:string]:T
};
export class Factory{
static ControlMap: ControlMap<any> = {};
static create<T extends AbstractControl>(c: { new ({}): T; }, options: AbstracControlOptions): T {
return new c(options);
}
}
Although class constructor seems to be called at c: { new ({}): T } but it does not actually calls it. But gets the reference to the constructor via new operator. The parameter {} to the constructor in my case is required because the base class AbstractControl requires it.
(1) Child Class(layout.ts)
import { Factory } from './factory';
import { Container, AbstracControlOptions } from './container';
export type LayoutlOptions = AbstracControlOptions & {
type:"layout";
}
export class Layout extends Container {
type: string = "layout";
constructor(options:LayoutlOptions) {
super(options);
}
}
Factory.ControlMap["layout"] = Layout;
(2) Child Class(repeater.ts)
import { Factory } from './factory'
import { Container, AbstracControlOptions } from './container';
export type RepeaterOptions = AbstracControlOptions & {
type: "repeater";
}
export class Repeater extends Container {
type: string = "repeater";
constructor(options:RepeaterOptions) {
super(options);
}
}
Factory.ControlMap["repeater"] = Repeater;