Executing a method on create for Stencil Components - javascript

I am working on a Stenciljs component where an array needs to be filled with fetch calls when the component is created. The array's contents will change throughout the component's life cycle. Right now the only way I can get it to be filled is by having a button that when clicked calls the fill method. How can I fill the array as the component is created or loaded so there is no user interaction required? In other words, how can I call the fill method without a button?
Thank you for your help.

You can use the Lifecycle Methods, in your case componentWillLoad is probably the right one.
componentWillLoad() {
this.fill();
}
You can also return a Promise which will prevent the component from rendering until the Promise is resolved.
There's also connectedCallback which will be called each time the component is added to the DOM (even if it moves).

Related

Change detection doesn't happen in synchronous codes

I was working on a component that has a button which toggles a boolean. This boolean is supposed to determine if a child component in the HTML need to re-render or not, since I want the ngOnInit function in the child to be re-run.
The situation is described in the app component here: https://codesandbox.io/s/angular-qxtm8
The app.component is the parent and second.component is the child.
I have tried three different solutions. They are onTestClickOne, onTestClickTwo, and onTestClickThree in app.component.ts. onTestClickOne and onTestClickTwo successfully re-triggers the ngOnInit in the child component. We can see the console log in it is printed on the console whenever I click the corresponding buttons. However, onTestClickThree didn't work.
I'm not 100% sure why onTestClickThree didn't work, and onTestClickTwo did.
My guesses are the following:
onTestClickTwo works because the change detection in Angular is run after the event handler has been executed. So, it will detect the boolean has been set to true. After that, the event loop will get the callback of the setTimeout and put it into the stack. Angular will execute change detection after finishing the callback.
onTestClickThree didn't work because, by the time Angular runs change detection, the boolean is already true. Angular doesn't know that it has been changed.
Let's tackle the main issue there, which is your design : why would you re-render the component to trigger ngOnInit again ?
Sure, in the case of your example, that's no big deal. But what happens for a fully coded component, making http calls, having children and all ? That will cause some severe performance issues.
Instead of re-rendering the component, you should use a function to do that.
If the event (that is initially supposed to re-render the component) comes from the child, then use an #Output. If it comes from the parent, use a #ViewChild reference.
As you can see it works well, without any detection issue.

Avoiding child rerender when parent runs setState

lHello everyone, here is the problem.
We have a grid component with some filtering enabled. When the filtering is applied, if a certain callback-prop exists, it is called with the filtered data as an argument.
The problem is this. If said datagrid is wrapped by a parent component and the parent component saves the filtered data in it's state, it causes the parent to rerender, but also the datagrid. However, when the datagrid renders it runs it's filtering logic, which causes the callback(which is setState() call) to run.
So, to avoid the loop I introduced a variable to the parent component class and save the data there, but it doesn't seem so good to me.
Another option would be redux, just add a new action and dispatch it when the filtering runs.
Any other ideas?
Since you're also asking for other ideas, may I suggest React hooks. They allow finer-grained control, such as multiple states, reducers, memoized callbacks, effects that are only called when inputs change, etc.

Angular change detection slow

I have a large array that I am using in a component (component A) with *ngFor with a nested *ngFor.
Component B initialises a jquery plugin which registers a document mousemove event handler, I am using this.zone.runOutsideAngular to init the plugin and I am calling this.ref.detectChanges() in the callback as I need to update the UI on mousemove inside the component B.
Component A is not a child of component B.
As soon as the component A is rendered change detection becomes very slow. the array does not change and I am using the ChangeDetectionStrategy.OnPush strategy for component A but when I fire ref.detectChanges() inside component B, ngDoCheck gets called on component A and I can see a noticeable jank on mousemove.
Is there a way to tell angular to completely ignore the large array of items in component A and allow me to handle when the UI should be updated? I thought that using ChangeDetectionStrategy.OnPush would give me what I need but I have tried removing all #Input()s from component A and anytime I call this.ref.detectChanges() inside component B it is still firing ngDoCheck and it is obvious that this is very slow.
I can scroll through the list of items no issue, but it is when I am triggering the detectChanges inside the mousemove on component B that is causing the issue. I know I could manually update the DOM but I think this would just be a workaround as it would only address the jank on mousemove and not the issue around the change detection being slow.
I have got to the bottom of this issue.
The problem was that inside component A for the nested *ngFor I was using a child component to render each sub item which meant that although I was using the ChangeDetectionStrategy.OnPush strategy, it still required a ref check for each item.
I have now moved the html from the child component into component A directly and this has had a huge impact on performance.
this.ref.detach() to remove the detector from from the tree completely, that should stop the checking. Then you can still call detectChanges to do it manually, and reattach to bring it back online.
Maybe also debouncing the mousemoves (rxjs debounceTime()) might help, unless you really need to track every mousemove?
One more optimization if you already didn't, add trackBy: yourTrackByFn to the ngFor(s).

How to reinitialize a package on each routing in Vue?

I've found a tool for table management and I love it. The only problem is that it needs initializing as shown below, which means that it only gets called once - when the page's been loaded.
mounted: () => {
$(document).ready(function () {
$("table").DataTable();
}
}
I've put the code in the mounted section and I also tried to use created. For some reason (probably rendering order), I have to keep it in ready method - otherwise it doesn't come up.
This poses two problems for me. Firstly, I'm reusing the same component as a matrix view in multiple components (it's dynamically set up based on the store). Secondly, when I navigate from the page and then go back, it doesn't reinitialize.
How should I make the code inside ready method to run each time the component gets in the view?
I've googled a bit but it's a not so common issue and I'm out of ammo. The best hit I got was the life cycle of the component where I couldn't see anything ground breaking. I also found that the data table instance needs to be destroyed but that only helps if I get to invoke the stuff, which seems not to happen.
I believe you just need to do following:
mounted () {
$("table").DataTable();
}
as $(document).ready detects that the document is ready, but in vue case, mounted is called after the instance has just been mounted where el is replaced by the newly created vm.$el, which should be equivalent of document.ready.
I have also checked in vue 2.x.x that mounted gets called if you navigate from the page and then go back.
If this code is dependent on data being loaded and re-rendering of component, you can use updated instead of mounted which is called after a data change causes the virtual DOM to be re-rendered and patched.
updated () {
$("table").DataTable();
}

React.js: Why is there no componentDidRender event?

I have just started using React, and a couple of times I have thought to myself: "Why is there no componentDidRender event?".
Say that I have a component that renders a table to the DOM, and I want to use bootstrap-sortable on this table to allow the user to sort on whatever column he wants. In the case of bootstrap-sortable you need to run $.boostrapSortable() after the table is drawn, in order to initialize the plugin.
As I see it, there are two handlers on a React component that would be logical to consider to use for this purpose:
componentDidMount: This does not work because the DOM does not seem to be updated at this point of the execution.
componentDidUpdate: This could possibly work, but it does not fire on the initial render.
I am not saying that React is actually missing a componentDidRender function, because I assume that there is a perfectly logical explanation as to why it is not there. I am just asking if someone could explain why such a function is not present, and what would be the "React way" to handle a case like the one above.
In componentDidMount you can do: this.getDOMNode() to get a reference to the underlying DOM for that component. So if you do want to use your mounted component with jQuery you can do:
componentDidMount: function() {
$(this.getDOMNode());
}
http://facebook.github.io/react/docs/working-with-the-browser.html
Here's a fiddle which shows jQuery acting on the DOM node of a react component:
http://jsfiddle.net/sa5e88ys/1/
As you can see, it adds a border to the div as expected. If you're still having problems I guess it could be with the plugin you're using rather than jQuery or react?
Although there's no componentDidRender, you can make a method with the desired behavior and call it in both componentDidMount (which is only called after the first render) and componentDidUpdate (which is called after every render but the first).
Also, this is the preferred way of getting a ref to a DOM node from within the component:
https://facebook.github.io/react/docs/refs-and-the-dom.html

Categories