Undefined functions when using mobx store with class instance as property - javascript

I am using mobx and decimal.js.
This is my store:
import Decimal from "decimal.js";
import { makeObservable, observable, action } from "mobx";
class MyStore {
public value: Decimal | null = null;
constructor() {
makeObservable(this, {
value: observable,
setValue: action,
});
}
public setValue() {
this.value = new Decimal(100);
}
}
export { MyStore };
This is my component:
import { useStoreValue } from "../../state/StoreContext";
import { observer } from "mobx-react-lite";
const MyPage = observer(() => {
const value = useStoreValue((rootStore) => rootStore.myStore.value);
return <span>{value.mul(5)}</span>;
});
export { MyPage };
As a result I get the following exception:
useObserver.ts:119 Uncaught TypeError: _value.mul is not a function
Any idea what I am missing?

Related

TypeError: Cannot read property 'products' of undefined Mobx React Native

Mobx giving me this error, and I don't know what is going on, there is no error in my code, what I make wrong? I tried so much fix this problem, hours and hours, someone knows what wrong I do??
stores/index.ts
import ProductStore from './product.store';
class RootStore {
products: ProductStore;
constructor() {
this.products = new ProductStore();
}
}
const store = new RootStore();
export {RootStore, ProductStore};
export default store;
stores/product.store.ts
import {WalmartApi} from '../api';
import {action, makeAutoObservable, runInAction} from 'mobx';
export default class ProductStore {
products = [];
constructor() {
makeAutoObservable(this);
}
#action
getProducts = async (searchQuery: string): Promise<void> => {
const snapshot = await WalmartApi.getProductsBySegment(searchQuery);
console.log({snapshot});
runInAction(() => {
this.products = snapshot;
});
};
}
hooks/userStores.tsx
import React from 'react';
import {MobXProviderContext} from 'mobx-react';
import store from '#stores';
export const useStores = (): typeof store => {
return React.useContext(MobXProviderContext).rootStore;
};
screens/Home.tsx
const {products} = useStores();
const onInit = () => {
products.getProducts('Playstation5');
};
useEffect(() => {
onInit();
});

Ngxs getState() after setState() returns empty always

Building state with ngxs in angular
//Component.ts
ngOnInit(): void {
const dataInsdeStore = this.store.selectSnapshot(MarketState);
if(!dataInsdeStore.loaded){
const category = this.marketplaceService.getMarketplaceCategories().subscribe(cat => {
const item = this.marketplaceService.getMarketplaceItems().subscribe(i => {
const obj = {
categories: cat,
items: i,
loaded: true
}
this.store.dispatch(new SetMarketAction(obj))
})
})
}
const test = this.store.selectSnapshot(MarketState);
this.store.dispatch(new GetMarketStateAction())
}
Upon checking wether the state is empty or not, and dispatching SetMarketAction I get empty object anyways
//Market.actions.ts
import { MarketStateInterface } from "../interfaces/interfaces";
class SetMarketAction {
static readonly type = '[MARKET] Set';
constructor(public marketState : MarketStateInterface){}
}
class GetMarketStateAction {
static readonly type = '[MARKET] Get';
}
export { SetMarketAction, GetMarketStateAction };
//Market.state.ts
import { Action, State, StateContext } from '#ngxs/store';
import { MarketStateInterface } from '../interfaces/interfaces';
import { Injectable } from '#angular/core';
import { GetMarketStateAction, SetMarketAction } from './market.actions';
#State<MarketStateInterface>({
name: 'market',
defaults: {
categories: [],
items: [],
loaded: false,
},
})
#Injectable()
export class MarketState {
constructor() {}
#Action(GetMarketStateAction)
getMarket(ctx: StateContext<MarketStateInterface>) {
const state = ctx.getState();
console.log(state);
return state;
}
#Action(SetMarketAction)
setMarket(ctx: StateContext<MarketStateInterface>, action: SetMarketAction) {
ctx.setState(action.marketState);
}
}
Every time I conosle.log the state at any given time I get the empty array, the interface of the state is correct

Method isn't available in unit test

I created new project in VueJS with TypeScript.
My component with methods to test:
<template>
<div></div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class Slider extends Vue {
private slide: number = 0;
private sliding: boolean = false;
public setSlide(slide: number): void {
this.slide = slide;
}
public setSliding(sliding: boolean): void {
this.sliding = sliding;
}
private onSliderStart(slide: any): void {
this.setSliding(true);
}
private onSlideEnd(slide: any): void {
this.setSliding(false);
}
}
</script>
Test:
import { shallowMount } from '#vue/test-utils';
import Slider from '#/components/Header.vue';
describe('Slider', () => {
const wrapper = shallowMount(Slider);
it('check Slider is a Vue Instance', () => {
expect(wrapper.isVueInstance()).toBeTruthy();
});
it('setSlide is func', () => {
expect(typeof wrapper.vm.setSlide).toBe('function')
})
});
and now I would like do test but methods setSlide, setSliding isn't available in wrapper :(
Try this:
import YourComponentHere from "#/components/YourComponentHere";
import { shallowMount, Wrapper } from "#vue/test-utils";
describe("test", () => {
const wrapper: Wrapper<YourComponentHere & { [key: string]: any }>;
it("does something", () => {
expect(wrapper.vm.someThingWhatever).toBe(true);
});
});
The advantage here is that you don't need to cast wrapper.vm to any everytime you use wrapper.vm
It seems you have to cast wrapper.vm as any for TypeScript not to complain:
it('setSlide is func', () => {
expect(typeof (wrapper.vm as any).setSlide).toBe('function')
})
Or at the top of your tests:
const wrapper: any = shallowMount(Slider);
Source: https://github.com/vuejs/vue-test-utils/issues/255#issuecomment-433312728.

Declare an arrow function as return in TypeScript

I want to write a TypeScript Declaration for ReactMeteorData.jsx which exports:
export default function connect(options) {
let expandedOptions = options;
if (typeof options === 'function') {
expandedOptions = {
getMeteorData: options,
};
}
const { getMeteorData, pure = true } = expandedOptions;
const BaseComponent = pure ? ReactPureComponent : ReactComponent;
return (WrappedComponent) => (
class ReactMeteorDataComponent extends BaseComponent {
...
}
);
}
Which is repacked as withTracker by react-meteor-data.jsx:
export { default as withTracker } from './ReactMeteorData.jsx';
I can simply declare the return value as Function:
declare module 'meteor/react-meteor-data' {
import * as React from 'react';
export function withTracker(func: () => {}): Function;
...
}
How can I declare what arguments and returns the Function creates without the need to change something in the origin package? So I would like to do something like:
export function withTracker(func: () => {}): (React.Component) => { React.Component };
Usage of the code is like this:
import * as React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
class Header extends React.Component<any,any> {
render() {
return "test";
}
}
export default withTracker(() => {
return { user: 1 };
})(Header);
Thank you!
The type you describe could be written like this:
(c: React.Component) => React.Component
In the section declare module:
export function withTracker(func: () => {}): (c: React.Component) => React.Component;

React with Flux: is this the dogmatic pattern or are there equal/better options?

I've recently learned how to code in React and how to structure the code using Flux. Unfortunately Firebase doesn't play to well with Flux and I need to set up a quick and easy back-end up for a prototype. Some suggest to forgo Flux altogether and to just use Firebase but I'm not sure if Flux will be almost necessary down the road when I hook up a real backend. If it is necessary, should I just force fit React into flux for now and unplug it later, or are there better alternatives to Flux out that I should be taking advantage of? Forgive the noob nature of this question. :)
Here is the basic reflux pattern I use starting with app.js;
import React from 'react';
import AppCtrl from './components/app.ctrl.js';
import Actions from './flux/Actions';
import ApiStore from './flux/Api.Store';
window.React = React;
Actions.apiInit();
React.render( <AppCtrl />, document.getElementById('react') );
app.ctrl.js
import React, {Component} from 'react';
import BasicStore from './../flux/Basic.Store';
var AppCtrlSty = {
height: '100%',
padding: '0 10px 0 0'
}
class AppCtrlRender extends Component {
binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }
render() {
var data = this.state.Data;
data = JSON.stringify(data, null, 2);
var data2 = this.state.Data2;
data2 = JSON.stringify(data2, null, 2);
var data3 = this.state.Data3;
data3 = JSON.stringify(data3, null, 2);
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
React 1.3 ReFlux with WebSocket<br/><br/>
{data}<br/><br/>
Data2: {data2}<br/><br/>
Data3: {data3}<br/><br/>
</div>
);
}
}
function getState() {
return {
Data: BasicStore.getData(),
Data2: BasicStore.getData2(),
Data3: BasicStore.getData3()
};
};
export default class AppCtrl extends AppCtrlRender {
constructor() {
super();
this.state = getState();
this.binder('storeDidChange');
}
componentDidMount() { this.unsubscribe = BasicStore.listen(this.storeDidChange); }
componentWillUnmount() { this.unsubscribe(); }
storeDidChange() { this.setState(getState()); }
}
Actions.js
import Reflux from 'reflux';
var apiActions = [
'apiInit',
'apiInitDone',
'apiSetData'
]
var wsActions = [
'gotData',
'gotData2'
]
var actionArray = wsActions.concat(apiActions);
module.exports = Reflux.createActions(actionArray);
Api.Store.js
import Reflux from 'reflux';
import Actions from './Actions';
import ApiFct from './../utils/ws.api.js';
function _apiInit() { ApiFct.init(); }
function _apiInitDone() { ApiFct.getData(); }
function _apiSetData(data) { ApiFct.setData(data); }
var ApiStoreObject = {
listenables: Actions,
apiInit: _apiInit,
apiInitDone: _apiInitDone,
apiSetData: _apiSetData
}
const ApiStore = Reflux.createStore(ApiStoreObject);
export default ApiStore;
ws.api.js. This is where you talk to firebase on the server. When you get data from the server just trigger the action to send the data to the store.
import Actions from '../flux/Actions';
module.exports = {
socket: {},
init: function() {
this.socket = new Primus();
this.socket.on('server:GotData', this.gotData);
Actions.apiInitDone();
},
getData: function() { this.socket.send('client:GetData', {}); },
gotData: function(data) { Actions.gotData(data); Actions.gotData2(data); },
setData: function(data) { this.socket.send('client:SetData', data); },
};
Basic.Store.js
import Reflux from 'reflux';
import Actions from './Actions';
import AddonStore from './Addon.Store';
import MixinStoreObject from './Mixin.Store';
var _data = {};
function _gotData(data) { _data = data; BasicStore.trigger(); }
function _addonTrigger() { BasicStore.trigger(); }
function BasicStoreInit() { this.listenTo(AddonStore, this.onAddonTrigger); }
var BasicStoreObject = {
init: BasicStoreInit,
listenables: Actions,
mixins: [MixinStoreObject],
onGotData: _gotData,
onAddonTrigger: _addonTrigger,
getData: function() { return _data; },
getData2: function() { return AddonStore.data2; },
getData3: function() { return this.data3; }
}
const BasicStore = Reflux.createStore(BasicStoreObject);
export default BasicStore;
The complete pattern is at https://github.com/calitek/ReactPatterns under React.13/ReFluxWebSocket.

Categories

Resources