property is being triggered before ngOnInit() in component - javascript

I'm new to Angular and I tried some code where the property set is being triggered before the ngOnInit().
export class App implements OnInit{
isTriggered = false;
constructor(){
...
}
ngOnInit(){
this.isTriggered = true;
}
}
I'm not sure how this works but isTriggered = false; is getting triggered first before the debugger moves to this.isTriggered = true;
Can someone explain me why this is happening and whats the approach to trigger this.isTriggered = true; from ngOnInit()

It's pretty obvious actually. To invoke ngOnInit you need an instance of App class. When you create an instance all declared fields are initialized first.

The issue is that ngOnInit is an Angular lifecycle method, whereas the isTriggered = false is a class property, native to Javascript, same as if you had placed it inside the constructor.
In the old way of doing things before Javascript Classes even came around, it might've been more obvious.
export function App() {
this.isTriggered = false;
this.ngOnInit = function() { };
}
Seen this way, it's pretty obvious that isTriggered = false will be invoked immediately upon creating a new App() vs. ngOnInit which will only be invoked by something calling ngOnInit after the new object is already created.
Angular lifecycle methods will happen on Angular's framework timing, meaning it's going to happen sometime after that class is initialized. During the initialization of that class, the class property will be set, hence why you see the debugger go to that line first.

When you declare isTriggered = false, that is the same as doing it as initializing it as if it was a part of the constructor. ngOnInit happens afterwards, so that's why you're getting it set to false and then to true.
You can declare isTriggered without assigning it a value simply by removing = false; and then only in ngOnInit assign it to true if that's what you're looking to do.

Related

Should I be binding also inbuilt React methods?

It is a common practice to be bind a user-created method inside a React.Component class.
class App extends React.Component { // simplified example, not actual code
constructor(){
//...
this.logIn=this.logIn.bind(this) // Binding of a method
}
}
Naturally, this is beceause we need to explicitly bind the method to "this class", otherwise we would be referencing with this the window object!
What's however unclear to me, least from the documentation and so on I viewed, if we use in-built life-cycle methods such as render() or componentDidMount(), majority of the code snippets and also the official documentation seem to not explicitly bind to this
class App extends React.Component {
constructor(){
//....
this.componentDidMount = this.componentDidMount.bind(this)
// is there reason why we don't do this ^ ??
}
}
Is there some in-built binding already inside the React.Component we extend?
Or why don't we need to explicitly bind the life-cycle methods (componentDidMount()) like the rest of our created methods (logIn())?
I've made a component with the following:
...
componentDidMount() {
var that = this;
var x = 0;
}
...
render() {
....
<button onClick={this.componentDidMount}>DID MOUNT</button>
....
}
And the results are in -- when the function does initially mount, that is properly bound, but when clicked from the button, it is not.
Which means that the componentDidMount is not already bound, but it is called from the React internals with the proper context so that it doesn't need to be bound.
-- edit
Perhaps also of note: it's worth checking if you use an autobind package, if that binds the lifecycle methods. autobind-decorator in fact does!
Naturally, this is beceause we need to explicitly bind the method to "this class", otherwise we would be referencing with this the window object!
You can also use arrow functions to been able to use this without binding:
sayHello=()=>{
return 'hello';
}
myOtherFunction=()=>{
console.log('I can acces the other function! Say:'+ this.sayHello())
}
And you don't need to bind the life-cycle methods
Edit: As the documentation says in https://reactjs.org/docs/handling-events.html
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
So it is supposed that lifecycle methods are bound by default.

Class properties for react lifecycle methods

Can I write React lifecycle methods as class properties?
I've been using class properties for a while as I like the fact that I no longer have to manually bind my methods, but I'd like to keep some consistency across my components and I'm wondering if there is any drawback on writing the React lifecycle methods as class properties
import React, { Component } from 'react';
class MyComponent extends Component {
render = () => {
return (
<div>Foo Bar</div>
);
}
}
export default MyComponent;
For example, is the context of this class property affected compared to the context in an equivalent method. Given that the render method in the above code is written as an arrow function, this concern seems relevant.
In a way, the true answer depends on your build pipeline and what the resulting Javascript output looks like. There are two primary possibilities:
Input Code
Let's start by saying you are writing the following before going through any sort of pipeline transformations (babel, typescript, etc):
class Test {
test = () => { console.log('test'); };
}
Output as class member variable.
In one possible world, your pipeline will also be outputting the test function as a member variable for the output class. In this case the output might look something like:
function Test() {
this.test = function() { console.log('test'); };
}
This means that whenever you write new Test() the test function is going to be recreated every single time.
Output as class prototype function
In the other major possibility, your pipeline could be recognizing this as a function property and escape it from the class instance to the prototype. In this case the output might look something like:
function Test() {
}
Test.prototype = {
test: function() { console.log('test'); }
}
This means that no matter how many times you call new Test() there will still be only one creation of the test function around in memory.
Desired behavior
Hopefully it's clear that you want your end result to have the function end up on the prototype object rather than being recreated on each class instance.
However, while you would want the function to not end up as a property, that doesn't necessarily mean you couldn't write it that way in your own code. As long as your build chain is making the correct transformations, you can write it any way you prefer.
Although, looking at the default babel settings (which your babeljs tag leads me to believe you are using) it does not make this transformation for you. You can see this in action here. On the left I've created one class with the function as a property and one class with the function as a class method. On the right hand side, where babel shows it's output, you can see that the class with the function as a property still has it being an instance-level property, meaning it will be recreated each time that class's constructor is called.
I did find this babel plugin, which seems like it might add this transformation in, but I've not used it for myself so I'm not positive.
In my experience, the most reason for writing a method as a class property is when the method will be passed as a callback, and you need it to always be bound to the instance. React lifecycle methods will always be called as a method, so there's no reason to bind them (and you incur a tiny memory penalty when you do). Where this makes a difference is when you're passing a function to a component as a callback (e.g. onClick or onChange).
Take this example:
class BrokenFoo extends React.Component {
handleClick() {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
The function represented by this.handleClick is not automatically bound to the component instance, so when the method tries to read the value of this.props it will throw a TypeError because this is not defined. Read this article if you're not familiar with this; the problem described in section 4.2 "Pitfall: extracting methods improperly" is essentially what's happening when you pass around a method without making sure it's bound correctly.
Here's the class, rewritten with the handler as a class property:
class HappyFoo extends React.Component {
handleClick = () => {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
Effectively, you can think of the handleClick definition in the second example as placing this code into the component's constructor (which is just about exactly the way Babel does it):
this.handleClick = () => {
alert(this.props.message);
}
This achieves the same thing as calling bind on the function (as described in the linked article) but does it a little differently. Because this function is defined in the constructor, the value of this in this.props.message is bound to the containing instance. What this means is that the function is now independent of the calling context; you can pass it around and it won't break.
The rule of thumb that I follow: by default, write methods as methods. This attaches the method to the prototype and will usually behave the way you'd expect. However, if the method is ever written without parentheses (i.e. you're passing the value and not calling it), then you likely want to make it a class property.

React functions and events

I am fairly new to react, I was looking at code and I ran into an event
code inside of a class that looked like
zipValueChanged(event) {
const zip = event.target.value;
this.setState({
zipValue: zip,
})
I was wondering why the event function does not have the function keyword anywhere, I did see a binding in the constructor ( this.zipValueChanged = this.zipValueChanged.bind(this);) However, I do not understand why this works.
Thank you so much!
This (this.zipValueChanged = this.zipValueChanged.bind(this);) binding in constructor was done so that any method defined in the class can work.
You need to bind your method in your constructor in order to work it properly -
this.yourFunction = this.yourFunction.bind(this);
This is the new syntax for Class methods definition. You can check out documentation here.
From now on inside a class you can define methods this way :
class A{
render() {
//your code here
}
}

Angular2 - Class property is undefined even though it is being set

I'm having the following, very simple angular2 Service:
#Injectable()
export class DrawingService {
private _draw:Draw;
constructor(private mapSvc:MapService) {}
initialize(geometry: GeometryType):void {
this._draw = new Draw(this.mapSvc.getMap());
this._draw.on("draw-end", this.addGraphic);
this._draw.activate(geometry);
}
addGraphic(evt):void {
this._draw.deactivate();
}
}
In initialize, I'm setting the method addGraphic as the callback. Now the problem is, that within the addGraphic method execution, this._draw is undefined.
What's the problem here?
If you pass a method reference like
this._draw.on("draw-end", this.addGraphic);
the reference to this points to the caller function.
If you use instead
this._draw.on("draw-end", this.addGraphic.bind(this));
it should work as expected.
Alternatively you can also use arrow functions but this requires to repeat the parameters (if there need any to be passed).
this._draw.on("draw-end", (param) => this.addGraphic(param));
Move the code to ngOnInit() instead of the constructor. You'll have to implement OnInit.

Aurelia binding: property-getter called repeatedly

I'm currently learning and using Aurelia and something kind of weird (maybe normal) is happening.
When using the following code
export class NavBar {
get username() {
console.log('o_o')
return 'name' + Date.now()
}
}
And in the template ${username}, the username is always updating, several times per seconds (and console.log are logged several times as well of course).
The workaround is to simply use a function and not a getter and call ${username()} in the template. But is this behaviour normal? So should I use sometimes getter sometimes not?
Thanks!
This is normal, Aurelia polls your property for changes because it has no way of knowing when your property-getter will return a different value.
If it were a simple property (without a getter), Aurelia could observe the property directly, no polling would be needed.
To avoid the polling you could tell Aurelia's binding system what to observe:
import {computedFrom} from 'aurelia-framework';
export class Foo {
_username = 'hello';
#computedFrom('_username')
get username() {
return this._username;
}
}
Another option would be to use a one-time binding:
${username & oneTime}

Categories

Resources