How to initiate a Standard Javascript Callback in Vue.js - javascript

How can I initiate this callback on Vue.js on page load?:
lightGallery(document.getElementById('lightgallery'));

One of Vue's life cycle hooks is beforeMount,
Your code can be:
beforeMount(){
lightGallery(document.getElementById('lightgallery'));
},

Use the initialization in your vue component with lifecycle hooks:
Vue.component('lightGallery', function() {
template: '<div>Place template markup here</div>',
mounted: function() {
$(this.$el).lightGallery();
}
});
Then you can just use the component:
<lightGalleryr></lightGallery>
There are different lifecycle hooks Vue provide:
I have listed few are :
beforeCreate: Called synchronously after the instance has just been initialized, before data observation and event/watcher setup.
created: Called synchronously after the instance is created. At this stage, the instance has finished processing the options which means the following have been set up: data observation, computed properties, methods, watch/event callbacks. However, the mounting phase has not been started, and the $el property will not be available yet.
beforeMount: Called right before the mounting begins: the render function is about to be called for the first time.
mounted: Called after the instance has just been mounted where el is replaced by the newly created vm.$el.
beforeUpdate: Called when the data changes, before the virtual DOM is re-rendered and patched.
updated: Called after a data change causes the virtual DOM to be re-rendered and patched.
You can have a look at complete list here.
You can choose which hook is most suitable to you and hook it to call you function like the sample code provided above.

Related

Angular - RxJS : afterViewInit and Async pipe

I tried to do the following in my component which uses changeDetection: ChangeDetectionStrategy.OnPush,
#ViewChild('searchInput') input: ElementRef;
ngAfterViewInit() {
this.searchText$ = fromEvent<any>(this.input.nativeElement, 'keyup')
.pipe(
map(event => event.target.value),
startWith(''),
debounceTime(300),
distinctUntilChanged()
);
}
And in the template
<div *ngIf="searchText$ | async as searchText;">
results for "<b>{{searchText}}</b>"
</div>
It doesn't work, however if I remove the OnPush, it does. I am not too sure why since the async pipe is supposed to trigger the change detection.
Edit:
Following the answers, I have tried to replace what I have by the following:
this.searchText$ = interval(1000);
Without any #Input, the async pipe is marking my component for check and it works just fine. So I don't get why I haven't got the same behavior with the fromEvent
By default Whenever Angular kicks change detection, it goes through all components one by one and checks if something changes and updates its DOM if it's so. what happens when you change default change detection to ChangeDetection.OnPush?
Angular changes its behavior and there are only two ways to update component DOM.
#Input property reference changed
Manually called markForCheck()
If you do one of those, it will update DOM accordingly. in your case you don't use the first option, so you have to use the second one and call markForCheck(), anywhere. but there is one occasion, whenever you use async pipe, it will call this method for you.
The async pipe subscribes to an Observable or Promise and returns the
latest value it has emitted. When a new value is emitted, the async
pipe marks the component to be checked for changes. When the component
gets destroyed, the async pipe unsubscribes automatically to avoid
potential memory leaks.
so there is nothing magic here, it calls markForCheck() under the hood. but if it's so why doesn't your solution work? In order to answer this question let's dive in into the AsyncPipe itself. if we inspect the source code AsyncPipes transform function looks like this
transform(obj: Observable<any>|Promise<any>|null|undefined): any {
if (!this._obj) {
if (obj) {
this._subscribe(obj);
}
this._latestReturnedValue = this._latestValue;
return this._latestValue;
}
....// some extra code here not interesting
}
so if the value passed is not undefined, it will subscribe to that observable and act accordingly (call markForCheck(), whenever value emits)
Now it's the most crucial part
the first time Angular calls the transform method, it is undefined, because you initialize searchText$ inside ngAfterViewInit() callback (the View is already rendered, so it calls async pipe also). So when you initialize searchText$ field, the change detection already finished for this component, so it doesn't know that searchText$ has been defined, and subsequently it doesn't call AsyncPipe anymore, so the problem is that it never get's to AsyncPipe to subscribe on those changes, what you have to do is call markForCheck() only once after the initialization, Angular ran changeDetection again on that component, update the DOM and call AsyncPipe, which will subscribe to that observable
ngAfterViewInit() {
this.searchText$ =
fromEvent<any>(this.input.nativeElement, "keyup").pipe(
map((event) => event.target.value),
startWith(""),
debounceTime(300),
distinctUntilChanged()
);
this.cf.markForCheck();
}
The changeDetection: ChangeDetectionStrategy.OnPush allow to the component to not triggered the changeDetection all the time but just when an #Input() reference is updated. So if you do all your stuff in the same component, no #Input() reference are updated so the view is not updated.
I propose you to Create your dumb component with your template code above, but give it the searchText via an #Input(), and call your dumb component in your smart component
Smart component
<my-dumb-component [searchText]="searchText$ | async"></my-dumb-component>
Dumb component
#Input() searchText: SearchText
template
<div *ngIf="searchText">
results for "<b>{{searchText}}</b>"
</div>
This is because Angular is updates DOM interpolations before ngAfterViewInit and ngAfterViewChecked. I know this sounds confusing a bit. It's because of the first change detection cycle Angular does. Referring to Max Koretskyi's article about change detection algorithm of Angular, in a change detection cycle these happens sequentially:
sets ViewState.firstCheck to true if a view is checked for the first time and to false if it was already checked before
checks and updates input properties on a child component/directive
instance
updates child view change detection state (part of change detection
strategy implementation)
runs change detection for the embedded views (repeats the steps in
the list)
calls OnChanges lifecycle hook on a child component if bindings
changed
calls OnInit and ngDoCheck on a child component (OnInit is called
only during first check)
updates ContentChildren query list on a child view component
instance
calls AfterContentInit and AfterContentChecked lifecycle hooks on
child component instance (AfterContentInit is called only during
first check)
updates DOM interpolations for the current view if properties on
current view component instance changed
runs change detection for a child view (repeats the steps in this
list)
updates ViewChildren query list on the current view component
instance
calls AfterViewInit and AfterViewChecked lifecycle hooks on child
component instance (AfterViewInit is called only during first
check)
disables checks for the current view (part of change detection
strategy implementation)
As you see, Angular updates DOM interpolations (at step 9) after AfterContentInit and AfterContentChecked hooks are called, so if you call rxjs subscriptions in AfterContentInit or AfterContentChecked lifecycle hooks (or earlier, like OnInit etc.) your DOM will be updated because Angular updates DOM at step 10, and when you change something in ngAfterViewInit() and you are using OnPush, Angular won't update DOM because you are at step 12 on ngAfterViewInit() and Angular has already updated DOM before you change something!
There are workaround solutions to avoid this to subscribe it in ngAfterViewInit. First, you can call markForCheck() function, so you basically say by using it on the first cycle that "hey Angular, you updated DOM on step 9, but I have something to change at step 12, so please be careful, have a look at ngAfterViewInit I have still something to change". Or as a second solution, you can trigger a change detection manually again (by triggering and event handler or using detecthanges() function of ChangeDetectorRef) so that Angular repeats all these steps again, and when it reaches at step 9 again, Angular updates your DOM.
I have created a Stackblitz example that you can try these out. You can uncomment the lines of subscriptions placed in lifecycle hooks 1 by 1, so that you can see after which lifecycle hook Angular updates DOM. Or you can try triggering an event or triggering change detection cycle manually and see that Angular updates DOM on the next cycle.

vue nexttick for map

I have a <div id="map" />
I have a mounted method in which I initialize map.
mounted(){
this.map = L.map(this.mapId, { preferCanvas: true }).setView(
[this.initialLatitudeOriginalPoint, this.intiialLongitudeOriginalPoint],
3
)
L.tileLayer(
tileconfig + '?access_token=' + key
{ maxZoom: 25, id: 'mapbox.streets' }
).addTo(this.map)
}
I have a prop called markers. and I have a watcher for it with immediate true
markers:{
handler(newVal, oldVal){
this.showMarkers()
},
immediate: true
},
Question- Looks like watcher gets called first. before mounted. Then showMarkers function throws error as map won't be defined because watcher got first before mounted. I really need immediate true for that watcher. Is there any way I can know that until map is not defined, watcher should wait?
What I think of: I think of using nextTick. but I don't understand one point about it. If I write this.$nextTick in my watcher's handler function, when will that nextTick callback be called? after dom got updated in this specific component or even in parent and parents of parents? if it doesn't care current component, then nextTick might be a little bit wrong in my case. I just want to understand this last thing about nextTick. any clue?
Firstly, you are correct that immediate will cause the watch to be triggered before the component is mounted. The role of watch is primarily to perform updates to properties based on other properties. So it will wait for all the basic properties (props, data, etc.) to be initialised but it assumes that rendering will need the output of the watch to render correctly. In your case this isn't true.
The way I would write this is:
mounted () {
// ... map stuff ...
this.showMarkers()
},
watch: {
markers: 'showMarkers'
}
If there needs to be a nextTick in there I'd be inclined to do that inside showMarkers rather than making it the caller's problem.
However, you don't have to do it this way. You can do it using immediate and nextTick, as suggested in the question.
So the key thing is to understand when exactly nextTick is called.
If a rendering dependency changes Vue will not re-render the component immediately. Instead it's added to a queue. Once all your other code has finished running Vue will process that queue. This is more complicated than it sounds as various components within the parent/child hierarchy may need updating. Updating a parent may result in the child no longer existing.
Once the queue has been processed and the DOM updated, Vue will call any nextTick callbacks. Any further changes that occur inside the callback will be added to a new rendering queue.
There are a couple of key points to note here.
While Vue may have updated the DOM, the browser won't actually paint all the new nodes until the JavaScript code has finished. That includes any nextTick callbacks. So if nextTick triggers further updates the user will not see the interim state of the page.
All of this is assuming that Vue is tracking the updates and performing the rendering. If you're doing rendering outside of Vue, as you are via Leaflet, then Vue can't do as much to help you.
So let's consider the following:
markers:{
async handler(newVal, oldVal){
await this.$nextTick()
this.showMarkers()
},
immediate: true
},
I've used async/await here rather than passing a callback but the end result is the same.
When the handler is called the first time it is before the component has rendered. The $nextTick will be called after all rendering has completed (including other components). So long as other components don't assume that the markers already exist this shouldn't be a problem, they'll still be created before the user sees anything.
When markers subsequently changes it may not actually trigger any rendering within Vue. Unless you're using markers somewhere within one of your templates it won't be a rendering dependency so no new rendering will be triggered. That's not necessarily a problem as $nextTick will still work even if there's nothing for Vue to render.

Difference between the created and mounted events in Vue.js

Vue.js documentation describes the created and mounted events as follows:
created
Called synchronously after the instance is created. At this
stage, the instance has finished processing the options which means
the following have been set up: data observation, computed properties,
methods, watch/event callbacks. However, the mounting phase has not
been started, and the $el property will not be available yet.
mounted
Called after the instance has just been mounted where el is replaced
by the newly created vm.$el. If the root instance is mounted to an
in-document element, vm.$el will also be in-document when mounted is
called.
This hook is not called during server-side rendering.
I understand the theory, but I have 2 questions regarding practice:
Is there any case where created would be used over mounted?
What can I use the created event for, in real-life (real-code)
situation?
created() : since the processing of the options is finished you have access to reactive data properties and change them if you want. At this stage DOM has not been mounted or added yet. So you cannot do any DOM manipulation here
mounted(): called after the DOM has been mounted or rendered. Here you have access to the DOM elements and DOM manipulation can be performed for example get the innerHTML:
console.log(element.innerHTML)
So your questions:
Is there any case where created would be used over mounted?
Created is generally used for fetching data from backend API and setting it to data properties. But in SSR mounted() hook is not present you need to perform tasks like fetching data in created hook only
What can I use the created event for, in real-life (real-code) situation?
For fetching any initial required data to be rendered(like JSON) from external API and assigning it to any reactive data properties
data:{
myJson : null,
errors: null
},
created(){
//pseudo code
database.get().then((res) => {
this.myJson = res.data;
}).catch((err) => {
this.errors = err;
});
}
For the created() hook, the data after manipulation in the browser it not shown in the DOM before mounted. In simple words the data takes time to manipulate the DOm seen the browser .
The mounted() hook is called after the DOM has been mounted or rendered which enables you to have access to the DOM elements and you can perform DOM manipulation.The best use for the mounted hook is if you need to access the DOM immediately before or after the initial render.

What are typical use cases for React lifecycle methods like componentWillReceiveProps

componentWillReceiveProps and other lifecycle methods seems like deceptive temptation to bring unnecessary complexity and noise to the code in the hands of inexperienced React coder. Why do they exist? What are their most typical use cases? In the moment of uncertainty, how would I know if the answer lies in the lifecycle methods?
I have been using react for couple of months now, and most of my work is creating a large application from scratch. So the same questions have presented themselves in the start.
The following information is based on learning while development and going through multiple docs out there to get it right.
As asked in the question here are couple of uses cases for the lifecycle methods in react
componentWillMount()
This is called once on the server side, if server side rendering is present, and once the client side.
I personally have used it just to do api calls which do not have direct effect on the components, for example getting oAuth tokens
componentDidMount()
This function is mostly used for calling API's (here is why to call it in componentDidMount and not in componentWillMount)
Components state initialisations which are based on the props passed by parents.
componentWillReceiveProps(nextProps,nextState)
This function is called every time props are received except the first render
Most common use I have encountered is to update the state of my current component which i can not do it in componentWillUpdate.
shouldComponentUpdate(nextProps, nextState)
This method is invoked before the render happens when new props or states are received. Here we can return false if the re-render is not required.
I see this as a performance optimisation tool. In case of frequent re-rendering of parent component this method should be used to avoid unnecessary update to current component
componentWillUpdate(nextProps,nextState)
this function is called every time a component is updated, it is not called when component mounts
Carry out any data processing here. For example, when a api fetch returns data, modelling the raw data into props to be passed to children
this.setState() is not allowed in this function , it is to be done in componentWillReceiveProps or componentDidUpdate
componentDidUpdate(prevProps,prevState)
Invoked right after the changes are pushed to the DOM
I have used it whenever the required data is not at the first render (waiting for api call to come through) and DOM requires to be changed based on the data received
Example, based on the age received show the user if he is eligible for application for an event
componentWillUnmount()
As the official docs mentions, any event listeners or timers used in the component to be cleaned here
In the moment of uncertainty, how would I know if the answer lies in
the lifecycle methods?
What analogy i suggest
Change is triggered in the component itself
Example, Enable editing of fields on click of an edit button
A function in the same component changes the state no involvement of lifecycle functions
Change is triggered outside of the component
Example, api call finished , need to display the received data
Lifecycle methods for the win.
Here are some more scenarios -
Does the change in state/props requires the DOM to be modified?
Example, if the current email is already present , give the input class an error class.
componentDidUpdate
Does the change in state/props requires to data to be updated?
Example, parent container which formats data received after api call and passes the formatted data to children.
componentWillUpdate
Props being passed to a child are changed , child needs to update
Example,
shouldComponentUpdate
Adding an event listener
Example, add a listener to monitor the DOM, based on window size.
componentDidMount
'componentWillMount' , to destroy the listner
Call api
'componentDidMount'
Sources -
Docs - https://facebook.github.io/react/docs/component-specs.html
this scotch.io article which cleared the lifecycle concepts
Event Listener - https://facebook.github.io/react/tips/dom-event-listeners.html
Some typical use cases for the most commonly used lifecycle methods:
componentWillMount: Invoked before initial rendering. Useful for making AJAX calls. For instance, if you need to grab the user information to populate the view, this is a good place to do it. If you do have an AJAX call, it would be good to render an indeterminate loading bar until the AJAX call finishes. I've also used componentWillMount to call setInterval and to disable Chrome's drag and drop functionality before the page renders.
componentDidMount: Invoked immediately after the component renders. Useful if you need to have access to a DOM element. For instance I've used it to disable copy and pasting into a password input field. Great for debugging if you need want to know the state of the component.
componentWillReceiveProps: Invoked when component receives new props. Useful for setting the state with the new props without re-rendering.
componentWillReceiveProps is part of Update lifce cycle methods and is called before rendering begins. The most obvious example is when new props are passed to a Component. For example, we have a Form Component and a Person Component. The Form Component has a single that allows the user to change the name by typing into the input. The input is bound to the onChange event and sets the state on the Form. The state value is then passed to the Person component as a prop.
import React from 'react';
import Person from './Person';
export default class Form extends React.Component {
constructor(props) {
super(props);
this.state = { name: '' } ;
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ name: event.currentTarget.value });
}
render() {
return (
<div>
<input type="text" onChange={ this.handleChange } />
<Person name={ this.state.name } />
</div>
);
}
}
Any time the user types into the this begins an Update for the Person component. The first method called on the Component is componentWillReceiveProps(nextProps) passing in the new prop value. This allows us to compare the incoming props against our current props and make logical decisions based on the value. We can get our current props by calling this.props and the new value is the nextProps argument passed to the method.

Does react rebuild or simply invoke render on children components in this case?

I am wrapping a 3rd party react component in my own react component.
Pretty standard stuff, here's the render method:
// my wrapper component scope
render: function () {
return React.createElement(ThirdPartyComponent, {
prop1: this.state.prop1, prop2: this.state.prop2 // etc
});
}
Some of my state variables trickle down to my child component as properties, so whenever I do a setState for one of my state variables render gets called.
Question: does ThirdPartyComponent get re-created from scratch every time render runs or after the first time it gets rendered by its parent is react just calling render on it instead of re-doing everything?
I kind of thought that (just calling render on the child) would be one of the points of react. I am getting a bit confused because I noticed that sometimes when my wrapper component renders some of the properties are picked up by the child component while others are ignored after the first time it renders.

Categories

Resources