Multiple action dispatches breaking API fetch request in redux app - sockets

I am building an app where I fetch data from a stock market api based on the tickers. I am using redux on the server and react+redux on the client and using sockets.io to communicate between the two.
The way I have set up the app is that, initially the state just gets populated with the list of tickers. No data is fetched regarding each ticker from the API. On the client side, whenever there is a state event emitted (which is emitted every time a new user connects to the socket), the following code on the client side dispatches an action
socket.on('state', state => {
store.dispatch({
type: 'SET_TICKERS',
state
});
});
Now, to actually fetch the data from the server side, I am dispatching an action from inside a component lifecycle hook on the client side
class StockList extends Component {
constructor(props){
super(props);
this.renderButton = this.renderButton.bind(this);
}
renderButton(stock){
return(
<button key={stock} type='button' className='btn btn-primary stock-btn'>
{stock}
<span className='glyphicon glyphicon-remove' aria-hidden='true'
onClick={() => this.props.onClick(stock)}></span>
</button>
)
}
render() {
if(this.props.stocks){
return (
<div>
{this.props.stocks.map(stock => {
return this.renderButton(stock);
})}
</div>
)
}else{
return(
<div>Loading...</div>
)
}
}
componentDidUpdate() {
console.log('The component did update');
console.log(this.props.stocks.toJS());
this.props.fillState(this.props.currentState);
}
}
I make the call from inside the componentDidUpdate function. This updates immediately after the state has been set with the list of tickers. However, the issue is that the componentDidUpdate lifecycle hook sends out far too many action requests, causing the api to crash. Why is this happening? Am I creating an infinite loop by sending out a dispatch from inside componentDidUpdate? Will throttling fix this?

I suppose executing this.props.fillState(this.props.currentState) updates parent component state, which cause parent render() method execution, so your component receives new props, which fire componentWillReceiveProps() method, which leads to componentDidUpdate() execution, so yeah - you created some kind of infinite loop.
To avoid that - you can use shouldComponentUpdate() method or change data flow of your component tree - I can tell that if pass currentState object and fillState function by props, you can as well fire this function and parent component (or use observer design pattern if you want child component to take part in this process).
I recommend you to read more about react component lifecycle

Related

Best way to send event from AngularJS parent component to Angular 7 child component? (ngUpgrade)

I have an AngularJS (1.7) app which is being migrated to Angular 7, using ngUpgrade. So the AngularJS and Angular frameworks are running at the same time, new components are written in Angular, and sometimes these modern Angular components are used inside of legacy AngularJS components.
In my case, the parent component needs to communicate with the child component in certain circumstances.
The ngUpgrade docs clearly show how to pass data and propagate events from the child Angular component to the parent AngularJS component:
<legacy-angularjs-component>
<div>{{ $legacyCtrl.whatever }}</div>
<modern-angular-child-component
[data]="$ctrl.initialDataForChildComponent"
(changed)="$ctrl.onChildComponentChanged($event)"
>
</modern-angular-child-component>
</legacy-angularjs-component>
To make that work, you just need to add a couple properties to the Angular child component: #Input() data; for the initial data, and #Output() changed = new EventEmitter<WhateverThing>(); that can then be used to propagate events to the parent component by doing this.changed.emit(this.whateverThing).
That all works, but what about propagating events from the parent to the child? I know how to do this in Angular, e.g. with #ViewChild or using observables, but those mechanisms are not available in my app's AngularJS environment. So the parent component cannot use them.
Two approaches I have tried that do work are:
Creating a separate service, which both components share.
Pass a reference to the parent controller into the child controller like this:
<legacy-angularjs-component>
<div>{{ $legacyCtrl.whatever }}</div>
<modern-angular-child-component
[observe]="$ctrl.registerObserver",
>
</modern-angular-child-component>
</legacy-angularjs-component>
...and then having the child component invoke this observe function:
ngOnInit() {
if (this.observe) {
// Pass reference to child component to the
// parent, so parent can directly send it messages.
this.observe(this);
}
}
This way, the parent has a direct reference to the child once the components are set up. The child implements some TypeScript interface that defines all the methods of the child that the parent can invoke to inform the child of events.
Both of those do work, but they both strike me as fairly kludgey and a lot of rigamarole to have to do for something as simple as sending an event to a child component.
Since this is easy to do in both AngularJS and Angular, I wondered if I might be missing an easier/simpler way to do the same thing in the context of ngUpgrade, where the parent is AngularJS and the child is Angular 7.
Or is my second approach a reasonable way to do it?
Well, as Eazy-E once said, "Ask, and ye shall immediately think of a simpler answer, right after you post the question in public."
A better solution than either of my first two mentioned above is to simply use regular Angular one-way bindings and use the OnChanges mechanism provided by Angular.
<legacy-angularjs-component>
<div>{{ $legacyCtrl.whatever }}</div>
<modern-angular-child-component
[observed]="$ctrl.valueThatChildIsObserving"
>
</modern-angular-child-component>
</legacy-angularjs-component>
Then, in the child component:
import { Component, Input, OnChanges, SimpleChanges } from '#angular/core';
export class MyChildCompoennt implements OnChanges {
#Input() observed: SomeWhateverObject;
ngOnChanges(changes: SimpleChanges) {
console.log(changes);
// Inspect changes (it contains old and new values
// for `observed` object. That object could be a string
// or something more complicated with multiple properties.\
}
}
This way, when the parent component wants to tell the child to do something, it can just do this.valueThatChildIsObserving = someWhatever;.
Angular will handle invoking the child componentngOnChanges(), passing it a structure containing the old and new value of the property.
You have to implement the child component so that it can inspect the changed value and execute the correct action, but that is pretty simple and avoids having to have the parent/child share references to each other.
I think this is a reasonably simple way to implement "propagate some kind of event from parent component to child component" in a hybrid AngularJS/Angular app using ngUpgrade.

Prevent re-targeting of events on LWC

Not able to get the event's original source on LWC.
Hi,
We are migrating an Aura component to LWC. We have a USE CASE, is being used in an iteration.
On click of , we are showing . The data in is dynamically retrieved based on record-id of .
In Aura, this was fairly simple because when fires an event, we can inject the data through method from grand parent to event.getSource().
But in LWC, the event is getting re-targeted on every parent-level bubbling. So finally event.target is returning the instead of .
Hence we are not able to inject data dynamically through event. What is the best approach for this scenario?
<!--c-todo-app>
<c-todo-item>
<div>
<!--Dynamic Iteration--Starts>
<c-todo-line-item>
<c-sub-item>
<c-todo-line-item>
<c-subitem>
--
...
...
...
--
<c-todo-line-item>
<c-subitem>
<!--Dynamic Iteration--Ends>
</div>
</c-todo-item>
Event.target OR event.currentTarget should give the source component but instead gives the top-most component below the handling component. In above example- event is fired in and handled in . Component returned is BUT we need

How do I properly update parent component from child form using props

I have a parent and child components
ShowreelApp.vue and Showreel.vue. I am passing properties over to the child when I create it.
<showreel-component
v-for="showreel in showreels"
v-bind="showreel"
:key="showreel.id"
#update="update"
#delete="del"
></showreel-component>
I then use the props to populate an update form in each child showreel.
<div class="showreel-input">
<label>Heading</label>
<input type="text" :value="myHeading" >
</div>
In the child form I am emiting an update event to the parent component to update the specific showreels data.
update(event) {
this.$emit('update', this.id, this.heading, this.subheading, this.youtubeid);
}
When the user clicks on the update button on the child Showreels components form I would like to send the data to the parent.
However I cannot bind the data to the child's input field as that causes the warning about mutating the property as I should not be updating the value from the child form.
One option I thought of was creating duplicates of each value in the child ... Updating them to the passed in props when its created , binding them to the form inputs... and then passing these values over to my parent using emit when updating.
But then these seems a bit convoluted to me and now I am thinking I have gone about this the wrong way. Any suggestions would be appreciated.
Mutating props from a child is usually not a very good practice but if you need it, as of version 2.3+ there is a .sync modifier. For more reference see Sync modifier
Another solution is to use event emitting or VueX. I would personally recommend Vuex but if you have relatively small application go with either sync or event emitting as you have described.
I should have mentioned that each showreel component has its own form fields and update button.
The solution I have come up with is to create a "sync" event in the parent and emit to it from the child
sync(id, property,value){
var currentShowreel = this.showreels.find(showreel => showreel.id === id);
currentShowreel[property] = value
},
The sync event calls a method in the parent which takes in and ID proprty name and property value.
This generic method is called from the child element inputs with a method
#keyup="sync('heading', $event.target.value)"
This calls a method in the child which in turn updates the parents data
},sync(property, value){
this.$emit('sync', this.id, property, value);
}
Then when the user updates I simply emit the update event to the parent. The parent grabs the particular showreel items data and updates based on the latest values.
It's working but not sure this is the right way of doing this.

Angular2 ControlGroup valueChanges on initial bind

I have a form with some <input type="text"> widgets and I have noticed that ControlGroup.valueChanges is being called upon initial databind when using [ngFormModel] and ngControl.
This means that the user thinks that the form has been changed upon initial load.
Is this normal or should I be using a different observable to track changes made the by the user?
I am using Angular2 RC3 and the following version import for forms:
import {ControlGroup, Validators, FormBuilder} from '#angular/common';
I think that's just how it works, however if you just want to track if changes are made by user, you should employ ControlGroup.dirty or formControl.dirty with the changes Observable.
ControlGroup.valueChanges.subscribe(() => {
if(ControlGroup.dirty){
console.log('This change is made by User.');
}
else {
console.log('This change is Automated. before any User interaction.');
}
})

jQuery on() click event handler with dynamic data crashing

Here's a simplified example of what I'm trying to achieve: http://jsfiddle.net/easLc/
HTML
<div class="bar">
<div class="apple"> apple</div>
<div class="banana"> banana</div>
<div class="citrus"> citrus </div>
</div>
jQuery
function showAlert(event) {
inventory = event.data.inventory;
alert(inventory);
}
fruits = ["apple", "banana", "citrus"];
inventory = [13, 45, 99];
for (i in fruits) {
$(".bar ."+fruits[i]).on("click", {inventory:inventory[i]},showAlert);
}
The inventory data I'm passing to the handler is dynamic, not static like the example. I'm getting the inventory data from asynchronous calls. After each time the inventory data is updated, I want to pass this data to the handler instead of have the handler get that information again.
What I'm noticing is on some clicks, the handler (I think) is crashing my browser. Am I creating too many handlers inadvertently? How do I see what handlers were created? Or what happens during the click event? I tried adding some console.log to the handler but I don't see them in the console.
Thanks!
Try
$(".bar ."+fruits[i]).off('click',showAlert).on("click", {inventory:inventory[i]},showAlert);
This will remove the previously bound event and rebind it... But it is hard to determine if it is the real source of the problem. You can add a console.log('text') in showAlert to see if it is being called more than once.
You can prevent multiple bindings by adding some sort of data to the element once it's been bound (a clean way would be a class, but meta-data may be preferred by standards):
$(".bar ." + fruits[i]).not(".bound").on('click', {...}).addClass('bound');