Guideline for memoized selectors in state base class - ngxs

I have a question regarding NGXS Store and the usage of memoized #Selector()s in a state class hierarchy.
What would be the recommended approach to the issue described below?
The NGXS Store documentation does not provide a guideline/recommendation in this regard.
Given this sample state setup,
export interface BaseModel { data: string[]; }
// base class not a state!
export class BaseState {
#Selector()
static dataSelect(state: BaseModel) { return state.data; }
// ...
}
export interface DerivedModel extends BaseModel {}
#State<DerivedModel>({ name: 'derived'; })
export class DerivedState extends BaseState {
// ...
}
export interface UsingModel { thing: number; }
#State<UsingModel>({ name: 'using'; })
export class UsingState implements NgxsOnInit {
constructor(private _store: Store) {}
ngxsOnInit(ctx: StateContext<UsingModel>) {
// have this state update when derived state changes
this._store.select(DerivedState.dataSelect).subscribe(data => console.log(data));
}
// ...
}
When letting this piece of code run it will print out undefined because the state argument
of the dataSelect(...) method will not be set.
I tracked the cause to BaseState not being a NGXS State and therefore missing an internal NGXS_META
property which in turn causes the undefined argument.
Adding BaseState to the selector (such as #Selector([BaseState])) to force the state to still be
included also does not have the desired effect, because now NGXS cannot navigate to a matching state slice.
I found two ways to make this work as desired:
1. duplicate the #Selector(...) method in every derived state implementation. This though defeats the reasons why the state class hierarchy was originally designed.
2. use something like #DerivedSelector(...) that works according to the standard decorator but dynamically creates selectors on use for each of the encountered derived state classes.
Thank you.

As far as I know this can not be achived using the #Selector annotation, but with createSelector().
export class BaseState {
static dataSelect() {
return createSelector(
[this],
(state: BaseModel) => {
return state.data;
}
);
}
//...
}
If you change your base state like this, your code will work. For details refer to the NGXS docs

Related

Mocking a class instantiated within the target class

I'm trying to write a Jasmine test for a function of class which instantiates and observes an object from another class. Since I want to keep this test contained to the first class and to simulate different scenarios of the second I want to mock the second. Some pseudo code might help
export class Foo {
startProcessing() {
const bar = new Bar();
const sub = bar.tickTock.subscribe(
state => {
// something went right
},
error => {
// something went wrong
}
);
}
}
I've tried declaring the mock class in my test file, and providing it through TestBed.configureTestingModule's providers attribute, but it always uses the original Bar.
How can I write a test that provides a mock class in place of Bar that I can control?
One way to get around this issue is to pass in object of type Bar through function parameter (dependency injection). That way you can have control over Bar object.

Angular 4: Using Custom RouteReuseStrategy causes Cannot read property 'prototype' of undefined

The custom Route reuse strategy is as follows,
import { RouteReuseStrategy,ActivatedRouteSnapshot,DetachedRouteHandler} from '#angular/router';
export class CustomRouteReuseStrategy extends RouteReuseStrategy {
shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; }
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; }
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle { return null ; }
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
console.log("inside shouldReuseRoute...");
return future.routeConfig === curr.routeConfig ;
}
}
I get this below error
Error: TypeError: Cannot read property 'prototype' of undefined
at __extends (http://localhost:8000/app/UMSClient/com/ipc/ums/modules/shared/CustomRouteReuse.service.js:7:73)
I read through stack overflow posts and couldn't locate a solution. Once this works I want to ensure one of my child component gets reloaded instead of Re-use and then attach component going forward in the project.
I provided in AppModule
{
provide: RouteReuseStrategy,
useClass: CustomRouteReuseStrategy
},
I change extends to implements and the error goes away but the custom route re-use does not work.
i am using angular 4.3.1
The issue was my workspace structure. Angular 2 version was picked up by build wrongly when angular 4 was intended. When I corrected this, it started working fine.

Which ReactJS syntax to use; React.createClass or ES6 extends?

I'm beginner of ReactJS. I learned and studied a lot of documents and ebooks on various websites. I realize there are two syntaxes for ReactJS. Example:
React.createClass({
displayName: 'Counter',
getDefaultProps: function(){
return {initialCount: 0};
},
getInitialState: function() {
return {count: this.props.initialCount}
},
propTypes: {initialCount: React.PropTypes.number},
tick() {
this.setState({count: this.state.count + 1});
},
render() {
return (
<div onClick={this.tick}>
Clicks: {this.state.count}
</div>
);
}
});
And this version is written by ES6:
class Counter extends React.Component {
static propTypes = {initialCount: React.PropTypes.number};
static defaultProps = {initialCount: 0};
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
state = {count: this.props.initialCount};
tick() {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div onClick={this.tick.bind(this)}>
Clicks: {this.state.count}
</div>
);
}
}
What is the better way to use ReactJS? But I found these libraries, application on github used to perform a lot ES6.
The second approach is probably the correct one to adopt going forward as Facebook have said they will ultimately deprecate the React.createClass approach.
From the React v0.13 release notes:
Our eventual goal is for ES6 classes to replace React.createClass completely, but until we have a replacement for current mixin use cases and support for class property initializers in the language, we don't plan to deprecate React.createClass
Personally I think the second approach also makes for easier to read code, but that is obviously a more subjective reason.
However, as stated above, it's important to note that the ES6 format does not support Mixins, so if you need a mixin you need to use the createClass format for that component.
This post "React.createClass versus extends React.Component" by Todd Motto has some good information on the difference between the two syntaxes. It's worth reading that for a discussion of how the this keyword behaves differently between the two syntaxes.
Edit: Dan Caragea's post below makes some excellent points that should definitely be considered too.
A third alternative...
There is a also a third way of defining a React component, called 'Stateless Functions' in the React Documentation and often called 'Stateless Functional Components' or 'Functional Stateless Components'. This is the example from the docs:
function HelloMessage(props) {
return <div>Hello {props.name}</div>;
}
Defining the component as a function means it is effectively created anew each time and so has no ongoing internal state. This makes the component easier to to reason about, and to test, as the component's behaviour will always be identical for a given set of properties (props), rather than potentially varying from run-to-run due the values of the internal state.
This approach works particularly well when using a separate State management approach such as Redux and ensures that Redux's time-travel will produce consistent results. Functional Stateless Components also make implementing features like undo/redo simpler.
I have done React.createClass for work and ES6 classes for my pet project. I do find the latter easier to read too but I often miss the simplicity/peace of mind I have with the former.
With the class based approach, do note that, technically, the statically defined propTypes and defaultProps are ES7, not ES6 - which might change until ES7 is finalized.
A pure ES6 approach would be to declare propTypes/defaultProps like
class Counter extends React.Component {
...
}
Counter.propTypes = {...};
Counter.defaultProps = {...};
You also have to remember to bind onClick in render (or any other method where you need to use this). It's almost certain you will forget to in some places. While with createClass all calls are auto-bound by React.
Another ES7 proposal could make things easier but you'd still need to remember to write it everywhere:
<div onClick={::this.tick}> which binds this to tick.
Of course, you'd have to opt in to stage 0 in babel config to make use of all these ES7 proposals.
About mixins...there are acceptable ways of using mixins with classes. A brilliant approach is mixWith.js but you could also try ES7 decorators, HOCs, even Object.assign() :)
At the end of the day, I feel that the class approach doesn't bring anything of real value and you could go the old and paved way of createClass until you have a good understanding of React. Then you can toy around with classes and ES6/7/100. It will be a long while before they deprecate createClass.
I started with React ES6 + staging style and it sounds nice when you say in React everything is a component. I like this class organization.
Because only methods can be defined inside ES6 class if you want to define properties in pure ES6 they have to be outside of the class. Like for instance in here:
export class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
tick() {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div onClick={this.tick.bind(this)}>
Clicks: {this.state.count}
</div>
);
}
}
Counter.propTypes = { initialCount: React.PropTypes.number };
Counter.defaultProps = { initialCount: 0 };
This is why in ES6 propTypes section is outside of the class definition.
But if you use ES7 you can define static and non-static properties without a problem inside of the class.
// ES7
export class Counter extends React.Component {
static propTypes = { initialCount: React.PropTypes.number };
static defaultProps = { initialCount: 0 };
state = { count: this.props.initialCount };
tick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div onClick={this.tick.bind(this)}>
Clicks: {this.state.count}
</div>
);
}
}
With ES7 you can use implicit binding tips for methods also as demonstrated in here:
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
The old pre React v0.13 style or ES5 style was like this.
In React.createClass all methods are bound this automatically.
This can be a little confusing for JavaScript developers because this is not native JavaScript behavior.
This is whe write:
class Counter extends React.Component {
constructor() {
super();
this.tick = this.tick.bind(this);
}
tick() {
...
}
...
}
or use some tricks to accomplish the same using property initializer syntax.
class Counter extends React.Component {
tick = () => {
...
}
...
}
Conclude
For the newcomers, I think the latest style is a better choice.
About Mixins
As stated here:
ES6 launched without any mixin support. Therefore, there is no support for mixins when you use React with ES6 classes.
We also found numerous issues in codebases using mixins, and don't recommend using them in the new code.
This section exists only for the reference.

how to define facade for a method that emits events in ScalaJS

I'm writing scalajs facade for pouchdb
code : https://gist.github.com/chandu0101/62013de47bf5ee4d2412
how to define facade for API name changes which emits events and return a cancel method ..
Defining Scala.js facade types is all about giving static types to a JavaScript API. Usually the documentation of the JavaScript does mention types, which can therefore be translated into a formal definition pretty easily.
In this case, the changes methods returns an EventEmitter, which is the first thing you need. Let us define this type, and in particular its on method:
class EventEmitter extends js.Object {
def on(event: String, listener: js.Function): this.type = js.native
...
}
We have to be very imprecise for the type of listener, unfortunately, because the actual type will very much depend on the event string, and the particular uses of that emitter. In general, we cannot predict anything at this point.
The documentation of EventEmitter doesn't mention a cancel() method, which is a bit weird since apparently that method can be called on the emitter returned by changes. So we'll define a subtype for the particular emitter returned by changes:
trait ChangesEventEmitter extends EventEmitter {
def cancel(): Unit = js.native
}
We can also take advantage of this specialized trait to enable a more precise type of listener for particular events. In this case, let us do it for the change event:
object ChangesEventEmitter {
implicit class ChangesEventEmitterEvents(
val self: ChangesEventEmitter) extends AnyVal {
def onChange(listener: js.Function1[js.Dynamic, Any]): self.type =
self.on("change", listener)
}
}
Finally, you need a type for the options parameter of the db.changes method. The type itself is usually a trait with many immutable fields:
trait DBChangesOptions extends js.Object {
val include_docs: js.UndefOr[Boolean] = js.native
val limit: js.UndefOr[Int] = js.native
...
}
To construct an instance of such a type, you may either go with an apply method in the companion object with default arguments (see this SO question), or you can create a Builder-like class for it.
And now, we can finally declare the changes method itself:
def changes(options: DBChangesOptions = ???): ChangesEventEmitter = js.native

Angular Dart component events

I am trying to pass custom events from a component to its parent component/controller
confirm.html
<div class="comfirm-component">
<content></content>
Yes
No
</div>
confirm.dart
#Component(
selector: "confirm-component",
templateUrl: 'confirm.html',
useShadowDom: false,
publishAs: "ctrl"
)
class ConfirmComponent {
void yes(){
print('yes');
// Fire confirm-yes event
}
void no(){
print('no');
// Fire confirm-no event
}
}
is there something like this?:
<confirm-component on-confirm-yes="doSomething()" on-confirm-no="doSomethingElse()">
Do you want to delete
</confirm-component>
I could use a normal StreamController but then i'd had to connect my components with code.
confirmComponent.onConfirmYes.listen()
confirmComponent.onConfirmNo.listen()
I also found this:
How to communicate between Angular DART controllers
And this:
angulardart components - dispatch custom event
In both treads scope.emit is mentioned. But i didn't find a way to use it with a component instead of a controller. Is there a full example vor angular.dart v0.14.0?
Is scope.emit the thing i'm searching for?
This should be the same, just add a scope argument to the constructor so the component gets the scope injected.
There was a related change in Angular 0.14.0 https://github.com/angular/angular.dart/commit/181f01448555c475869505491159045904e5dc89
I haven't yet tried this.
From the description you need to implement ScopeAware
#Component(...)
class MyComponent implements ScopeAware {
Watch watch;
MyComponent(Dependency myDep) {
// It is an error to add a Scope / RootScope argument to the ctor and will result in a DI
// circular dependency error - the scope is never accessible in the class constructor
}
void set scope(Scope scope) {
// with this scope you should be able to use emit
// This setter gets called to initialize the scope
watch = scope.rootScope.watch("expression", (v, p) => ...);
}
}
Based on the answer from Günter i built this working example:
#Component(
selector: "confirm-component",
templateUrl: 'component/confirm.html',
useShadowDom: false,
publishAs: "ctrl"
)
class ConfirmComponent implements ScopeAware {
Scope scope;
void yes(){
scope.emit('confirm', 'yes');
}
void no(){
scope.emit('confirm', 'no');
}
}
#Component(
selector: "my-component",
templateUrl: 'component/my.html',
useShadowDom: false,
publishAs: "ctrl"
)
class MyComponent implements ScopeAware{
void set scope(Scope scope) {
Stream mystream = scope.on('confirm');
mystream.listen((event){
print('confirmed: ' + event.data);
});
}
}

Resources