I'm trying to write getters and setters into an observable array and it isn't working. The code below gives me the following error: Error: [MobX] No annotations were passed to makeObservable, but no decorator members have been found either
I've tried different combinations of decorators, but nothing seems to work. The behavior I want is whenever AppModel.text is updated, any UI rending the getter for text should update. Also whenever gonext() is called on the object, then any UI rending from AppModel.text should update and render data from the new 0 item on the array.
class DataThing
{
#observable text?: string = "foo";
}
class AppModel
{
get text() { return this.items[0].text}
set text(value: string | undefined) { this.items[0].text = value;}
items: DataThing[] = observable( new Array<DataThing>());
constructor() {
makeObservable(this);
this.items.push(new DataThing());
}
gonext() { this.items.unshift(new DataThing()); }
}
EDIT:
I ended up doing the following, but would still like to understand how to index into an array in an observable way.
class DataThing
{
#observable text?: string = "zorp";
constructor(){makeObservable(this);}
}
class AppModel
{
#observable _current?:DataThing;
get current() {return this._current;}
items: DataThing[] = observable( new Array<DataThing>());
constructor() {
makeObservable(this);
this.gonext();
}
gonext() {
this.items.unshift(new DataThing());
this._current = this.items[0];
}
}
I have a component with a viewport property. I want to listen for changes to this property, do some calculations and reflect a possibly changed value back to the property. My first attempt looked something like this:
class MyComponent {
#Prop()
viewport: ViewportData
#Watch('viewport)
viewportChanged(newValue: ViewportData, oldValue:ViewportData) {
... do some calculations
// Reflect value back as property
this.viewport = computedViewport;
}
}
This results in a stack overflow because reflecting the value back triggers another call to the watch function. I could prevent it by having a flag saying if this is an internal change or not. Something like this:
class MyComponent {
internalViewportChange = false;
#Prop()
viewport: ViewportData
#Watch('viewport)
viewportChanged(newValue: ViewportData, oldValue:ViewportData) {
if (this.internalViewportChange) {
this.internalViewportChange = false;
return;
}
... do some calculations
// Reflect value back as property
this.internalViewportChange = true;
this.viewport = computedViewport;
}
}
I don't like this approach. And is looking for something better. This problem could normally be solved by using getters and setters and a private variable keeping the actual state:
class MyComponent {
private _viewport: ViewportData
get viewport() {
return this._viewport;
}
set viewport() {
... do some calculations
// Reflect value back as property
this.viewport = computedViewport;
}
}
However, using Stenciljs the getters and setters are autogenerated. Any good ideas?
I'd probably break the two-way prop setting, and
create a unidirectional data flow, and emit events instead. Something like:
class MyComponent
#Event() viewportChanged: EventEmitter;
#Prop() viewport: ViewportData;
#State() _computedViewport: ViewportData;
#Watch('viewport') onViewportChanged(newValue) {
// do calculations
this._computedViewport = computedViewport;
this.viewportChanged.emit(this._computedViewport);
}
Internally, you'd only work on _computedViewport, and the public viewportProp is only there for users to update themselves. Ostensibly you could also expose a #Method() that does the same thing.
I need to update my view on changing array in my *.component.ts
I use
public getFolders() : void {
this.webService.getFolders({client_id : this.local.get('clientUser').client_id}).subscribe( this.processSkills.bind(this, this.local.get('clientUser')))
}
processSkills(res: any, myobj): void {
if(res.status){
myobj.folders = res.folders;
this.local.set('clientUser', myobj);
this.userObj = this.local.get('clientUser');
}
}
It updates my array i saw in console it update my session value which i saw after pressing F5 but it doesn't update my view
Initially i am assigning my array to variable from my session object.
import { BehaviorSubject } from 'rxjs';
private messageSource = new BehaviorSubject(this.local.get('clientUser'));
currentMessage = this.messageSource.asObservable();
I resolved it and found a solution to pass our array into session and make the code into our provider which works as observable to my array and then recieve
currentMessage to our receiver function to update on view.
this.webService.currentMessage.subscribe(message => {
this.userObj = message;
})
will receive updated value and will reflect on view.
Using AureliaCLI and TypeScript.
I have a service which returns a specific type and a component which incorrectly assigns the returned object to a variable of another type:
import { ItemService } from "./itemService";
import { Item } from '../server/backend';
export class ItemDetails {
item: Item = null;
constructor(private itemService: ItemService) {
}
activate() {
this.item = this.itemService.getItem();
}
}
and
import { Seat } from "../server/backend";
export class ItemService {
item: Seat;
constructor() {
this.item = null;
}
getItem(){
return this.item;
}
setItem(item: Seat){
this.item = item;
}
}
This will generate an error when 'au run --watch' is run the first time, but any subsequent change to either file does not produce an error.
Can I configure AureliaCLI to look at dependant files also?
Thanks
Right, as you can probably guess, I am new to TypeScript.
I forgot to add a return type to the service method...
This will cause the error to be triggered:
getItem(): Seat {
return this.item;
}
I'm new in react native.I want store multiple small small strings to common singleton object class and want to access it from singleton object for all component. Can anyone help me singleton object implementation for react native.
Ex
Component 1 -- Login button -- >> success --> need to store userID into singleton object.
Component 2 --> get stored userID from singleton object. How can i implement it.
Here is a simple way of doing it...
export default class CommonDataManager {
static myInstance = null;
_userID = "";
/**
* #returns {CommonDataManager}
*/
static getInstance() {
if (CommonDataManager.myInstance == null) {
CommonDataManager.myInstance = new CommonDataManager();
}
return this.myInstance;
}
getUserID() {
return this._userID;
}
setUserID(id) {
this._userID = id;
}
}
And here is how to use it...
import CommonDataManager from './CommonDataManager';
// When storing data.
let commonData = CommonDataManager.getInstance();
commonData.setUserID("User1");
// When retrieving stored data.
let commonData = CommonDataManager.getInstance();
let userId = commonData.getUserID();
console.log(userId);
Hope this works out for you :)
I suggest making a static class that stores data using AsyncStorage.
You mentioned in a comment that you are already using AsyncStorage, but don't like spreading this functionality throughout your app. (i.e. try-catches all over the place, each component needing to check if a key is available, etc.) If this functionality were in a single class, it would clean up your code a lot.
Another bonus to this approach is that you could swap out the implementation pretty easily, for example, you could choose to use an in-memory object or AsyncStorage or whatever and you would only have to change this one file
NOTE: AsyncStorage is not a safe way to store sensitive information. See this question for more info on the security of AsyncStorage and alternatives.
That said, this is how I imagine a global data holder class might look:
export default class dataManager {
static storeKeyValue(key, value) {
// your choice of implementation:
// check if key is used
// wrap in try-catch
// etc.
}
static getValueForKey(key) {
// get the value out for the given key
}
// etc...
}
Then to use this class anywhere in your app, just import wherever it's needed like so:
import dataManager from 'path/to/dataManager.js';
// store value
dataManager.storeKeyValue('myKey', 'myValue');
// get value
const storedValue = dataManager.getValueForKey('myKey');
EDIT: Using Flux, Redux, or a similar technology is probably the preferred/suggested way to do this in most cases, but if you feel the Singleton pattern works best for your app then this is a good way to go. See You Might Not Need Redux
There is a workaround for this, react native packager require all the modules in the compilation phase for a generating a bundle , and after first require it generates an internal id for the module, which is from then on referenced in the whole run-time memory , so if we export an instance of a class from the file, that object will be referenced every-time whenever that file is imported .
TLDR;
Solution I :
class abc {
}
module.exports = new abc()
Solution II : I assume you want to get your strings which are static and wont change , so you can declare them as static and access them directly with class name
FYI :this works with webpack also.
I might be too late for this, but I might as well share my own implementation based on Yeshan Jay's answer.
export default class Data {
static instance = null;
_state = {};
static get inst() {
if (Data.instance == null) {
Data.instance = new Data();
}
return this.instance;
}
static get state() {
return Data.inst._state;
}
static set state(state) {
Data.inst._state = state;
}
static setState(state) {
Data.inst._state = {...Data.inst._state, ...state}
}
}
And here's how you use it. It's pretty much mimicking React Component's state behavior, so you should feel at home with little to no adjustment, without the need to frequently modify the Singleton to add new properties now and then.
import Data from './Data'
// change the whole singleton data
Data.state = { userId: "11231244", accessToken: "fa7sd87a8sdf7as" }
// change only a property
Data.setState ({ userId: "1231234" })
// get a single property directly
console.log("User Id: ", Data.state.userId)
// get a single property or more via object deconstruction
const { userId, property } = Data.state
console.log("User Id: ", userId)
TS Class Example:
export class SingletonClass
{
private static _instance: SingletonClass;
public anyMetod(_value:any):any
{
return _value;
}
public static getInstance(): SingletonClass
{
if (SingletonClass._instance == null)
{
SingletonClass._instance = new SingletonClass();
}
return this._instance;
}
constructor()
{
if(SingletonClass._instance)
{
throw new Error("Error: Instantiation failed: Use SingletonClass.getInstance() instead of new.");
}
}
}
Use:
SingletonClass.getInstance().anyMetod(1);