Increase performance on Angular2 inputfield - performance

I have a list of components that contain dates(formatted with toLocaleString()) and other things. On top of them there is a component for creating new components, wich contains a form with some inputfields built with angulars FormBuilder.
When I type fast the validation lags and the text I'm typing isn't displayed immediately.
I assume that Angular is rerendering all components, because if I don't display the date in the other components I can type pretty fast without lags.
Is there a way to only rerender the input field I'm typing in, since all other components cannot change or is toLocaleString() the problem?

Is there a way to only rerender the input field I'm typing in, since all other components cannot change
Yes, for the components that will not change, set the change detection strategy for those components to OnPush. An OnPush component will then only be checked for changes if
any of its input properties changes
it fires an event (e.g., a button click)
an observable (which is an input property or a local-to-the-component property) fires an event, and | async is used in the template with the observable (see plunker in the comments below this answer)
import {Component, Input, ChangeDetectionStrategy} from 'angular2/core';
#Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
})
Also consider listening for changes to your input by subscribing to the valueChanges Observable Angular makes available on your form element if you use ngFormControl. You can then use debounce() to only process changes every second or whatever time frame is appropriate:
<input type=text [ngFormControl]="input1Control">
constructor() {
this.input1Control = new Control();
}
ngOnInit() {
this.input1Control.valueChanges
.debounceTime(1000)
.subscribe(newValue => console.log(newValue))
}
See https://stackoverflow.com/a/36849347/215945 for a working plunker.

That's a known issue https://github.com/angular/angular/issues/6311
See also
https://github.com/angular/angular/issues/5808
https://github.com/angular/angular/issues/7822
https://github.com/angular/angular/issues/7971
There is also a pull request with a proposed fix, but seems not to be included in the latest beta release.

Related

MUIInputLabel does not grow when TextField is empty

The TextFields in the Material-UI docs has the label which grows and shrinks depending on whether there's a value in the field.
Rather than a user input, I am trying to use JS to reset my TextField to "" when a button is pressed. This means if a user has keyed data into the TextField, if they press the reset button, the field is cleared while the label grows to refill the field.
What is happening is that while my data is cleared, the label remains small.
Where am I going wrong with this?
I've read that it's related to something called shrink, but I dont understand how its called.
A portion of my code, built using Material-UI and ReactJS
EntryField component
<TextField onChange={inputChangedHandler} label={props.label} value={props.value} type={props.type} required={props.required} name={props.name} id={props.id} inputRef={props.propsRef} />
Form component, which uses the EntryField component above, as well as the ReactJS
const refNumRef = useRef();
const [objRefNum, setRefNum] = useState();
(...)
function resetData(event){
setRefNum('')
}
(...)
<EntryField label="Ref Number" type="text" editData={setRefNum} value={objRefNum}
id="input_refNum" name="refNum" propsRef={propRefNumRef} />
So....after posting my question, I made more trial and errors and I somehow managed to get it to work; Im not sure why.
But the main change I made was setting a default to the useState like so
const [objRefNum, setRefNum] = useState("");
And somehow this managed to fix not just this issue with the TextField, but an issue Ive been having with a Select statement as well, where I had trouble resetting it to a default value.
I will eventually have to figure out how to declare this programmatically based on API calls where the default value will change based on the results........but this is fine for now.

how to make a React component intelligently dispatch a Redux action on user interaction, without passing props that don't affect visual appearance

TL/DR: React components have two kinds of code:
rendering code that draws the component, which depends on certain props that affect the component's visual appearance (call them "visual props"), and
event-handling code, e.g., onclick handlers, which depends on certain props that don't affect the component's visual appearance (call them "event props").
When event props change, they cause the component to re-render, even though its appearance doesn't change. The only thing changing is its future event-handling behavior.
What's best practice for removing event props to avoid unnecessary re-renders, while still allowing intelligent event handling?
Longer version
My question is subtly different from this question about how to give handlers to dumb React components; see below for explanation.
I have an application with many React components (hundreds to thousands of SVG elements; it's a CAD application).
There are many "edit modes" in this application (imagine a drawing program like Inkscape): depending on the edit mode, you might want a left-click to select an object, or drag to draw a selection outline rectangle, or do any number of different edits to the component that was clicked, depending on the edit mode.
In my original architecture, every one of these components had the current edit mode as a prop. Each component would use the mode prop to decide what to do in response to events such as clicks: different sorts of Redux actions are dispatched in response to clicks depending on the current mode. This means that every time the user switches the edit mode, every component gets re-rendered, even though none of them change visually. In a large design, it takes several seconds to re-render.
I've altered it to improve performance. Now, each component is dumber: none of them know the edit mode. But this means they don't know what to do in response to a click. In some cases, I solved this by having each dispatch a "dumber" action that says essentially "I was clicked". Middleware intercepts this action, looks up the edit mode in the Redux store, and dispatches an appropriate smart action based on the edit mode. In other cases, I simply let the component dispatch the original action (e.g., Select), even if that action may not be valid for the current edit mode, and similarly rely on the middleware to intercept and stop the action if it is invalid for the current edit mode.
This solution feels inelegant. Now, many more actions get dispatched, even though most of them are thrown away. It's also nothing like what I find in introductions/tutorials to middleware, which mostly talk about how it's good for async stuff (I don't need any of this to be asynchronous since these actions generally are not talking to the network or files) and side-effects such as logging (no side-effects here; I simply want a user interaction to trigger a normal Redux action to be dispatched).
I feel as though a better solution would be to access the Redux store as a global variable within event handling code. I know this is emphatically not safe to do with rendering code, since it breaks the rule "React views should be a deterministic function of their props and state". But it feels safer to do with event-handling code.
I realize it's common with "very dumb" React components to pass click handlers in as a prop (e.g., this stackoverflow answer), but I don't see this as a solution. If handler has the edit mode encoded in it as a bound value, then the handler itself needs to change when the edit mode changes, which, since the handler is a prop, requires re-rendering the component. So I think this issue I'm describing is orthogonal to whether the handler is passed into the component as a prop, or written specifically for the component.
So to summarize, there's three options I see:
Pass all data required for intelligent event handling as props. (causes unnecessary re-renders)
Have React components dispatch actions "promiscuously", and rely on middleware (which has access to the Redux store) to stop and/or transform the action if necessary. (As I implemented it, is harder to understand, and puts lots of unrelated application logic in one place, where it feels like it doesn't belong. Also makes for a messier Redux history of actions, making it harder to debug using Redux DevTools, and is not a pattern I've seen in any documentation/tutorial on Redux middleware.)
Allow event handler code (unlike rendering code) to access the Redux store as a global variable, to make intelligent decisions about what action to dispatch. (Seems okay, but scares me to use global variables in this way, and I'm worried that it could cause a problem I'm not seeing.)
Is there a fourth option I'm missing?
I have an idea for how to solve this in a way that feels close to the Redux spirit. (Though I still lean towards accessing global variables in event handlers to solve the problem.)
Redux has some notion of "action creators", which is a function that returns an action object. This always seemed like an unnecessary layer of abstraction to me. But perhaps a similar idea can be used here. (I use Dart, not Javascript, so the code below is Dart; hopefully the answer makes sense.)
The idea is to have a new type of action in called ActionCreator<A extends Action> (subtype of Action). An ActionCreator<A> is an object with a method of type
A create(AppState state)
In other words, it takes the whole AppState and returns an Action. This lets it do the necessary data lookups. As an object, it can contain fields that describe data gathered from the code (usually View event handler code) that instantiated it. For example, it could reference a Selectable to select. create() returns either null or some special value to indicate that the action should be thrown away.
For example, if we have a click handler, we'd dispatch an ActionCreator
class Select {
final Item item_clicked;
Select(this.item_clicked);
}
class ClickedAction implements ActionCreator<Select> {
final Item item_clicked;
ClickedAction(this.item_clicked);
Select create(AppState state) =>
state.ui_state.select_mode_is_on ? Select(this.item_clicked) : null;
}
// ...
onClick = (event) {
props.dispatch(ClickedAction(props.item));
}
And in middleware, once we have access to the full state, this can be turned into a concrete action, but only if it's legal. But the nice thing is that the next piece of code is generic and handles any such ActionCreator, so I wouldn't have to remember to keep editing this code whenever I create a new Action that needs to be "conditionally dispatched".
action_creator_middleware(Store<AppState> store, action, NextDispatcher next) {
if (action is ActionCreator) {
var maybe_action = action.create(store.state);
if (maybe_action != null) {
dispatch(maybe_action);
}
} else {
next(action);
}
}
The disadvantage of this is that it's still dispatching many more actions than we really need; most will get thrown away. It's a "cleaner" implementation of what I need, but I still think that for asynchronous event handlers, access the Redux store as a global variable is probably perfectly fine. I don't see in that any of the problems one would expect if the view code went outside of its React props and accessed global variables.

Redux-form field with input component re-renders on first character causing the keyboard to collapse

I have a form which is made using some logic, loading components from an external API.
This was working great using redux-form 6.3.2 and react 16.0.0-alpha.12.
The app is built with expo and I had to update expo SDK to the latest, which updates react to 16.3.1 and forced me to update redux-form. Since I had to update I went to the latest version (7.3.0) which led to some issues in the app that I was able to fix, but for this one I can't find a solution:
The forms is created using fieldArray and Field, so the createElement, after some processing does this:
return fieldObj.fields ?
(<View key={idx} style={style}>
<FieldArray {...fieldObj}
key={idx}
name={fieldObj.name}
component={component} />
</View>)
:
(<Field {...fieldObj}
key={idx}
style={style}
type={fieldObj.type}
name={fieldObj.name}
component={component} />);
And we get component using a formWrapperHOC:
formLib.FormWrapperHOC(formElement, {
onChangeCB,
onBlurCB,
stylesKeys,
formName,
extraProps,
})
which in turn does some things until it renders:
//FormWrapperHOC render method:
render() { return (<WrappedComponent {...this._massageProps()} />); }
So when I insert the first character in this input I see the events:
##redux-form/FOCUS
##redux-form/CHANGE
##redux-form/UPDATE_SYNC_ERRORS
##redux-form/REGISTER_FIELD
##redux-form/UNREGISTER_FIELD
I tried removing validations, so UPDATE_SYNC_ERRORS is not called, but item still rerenders.
Another thing that caught my eye is that the field is registered and later unregistered.
I end up with the input field and the character I entered, but keyboard is collapsed. If I focus on the field again everything works as expected: No call to UPDATE_SYNC_ERRORS because the field already has some content on, only CHANGE is triggered.
Since this works fine with redux-form 6.3.2, I'm pretty sure I need to make a change in my code for it to work with redux-form 7.3.0. Thing is, I was not able to find where is the issue, so any help or lead for where to look will be greatly appreciated.

Reliable way to access data in Polymer (inside dom-repeat / event handler)

I need to capture data from an instance generated by <template is="dom-repeat"> in Polymer (v1.2.4) and I am not sure what would be the safest way to do so considering the myriad of Shadow DOMs available (client browser might be polyfilled etc).
A simple example:
<template is="dom-repeat" items="[[myItems]]" id="collection">
<paper-card on-tap="handleTap">
(...)
What is the most reliable way to access the model data from the event handler?
1.
handleTap: function(e) {
var data = e.model.get('item.myData');
}
2.
handleTap: function(e) {
var data = this.$.collection
.modelForElement(Polymer.dom(e).localTarget)
.get('item.myData');
}
My concern is that the simplest (#1) option might be working as expected in my environment but can get buggy in other browsers.
And even in option #2, I am not confident if it is really necessary to normalize the event target (as recommended in the official Polymer guide on events) prior to passing it to modelForElement.
Both should work; but, it seems you should fire a custom event though over trying to inspect a child model. What ever component that has "item.myData" should fire a custom event on tap with "item.myData" as part of the event. Then you should setup a listener for that custom event.
See custom events for more details.

Knockout - Disabling the default behavior of updating model when using binding value with form element

Knockout has the default behavior of updating the associated model if you change your focus (e.g. by clicking outside the input control) after editing the value inside an input control, populated by a binding of type Value.
Here is the link to the official documentation page explanation, section Parameters:
http://knockoutjs.com/documentation/value-binding.html
Do you know a way to disable this default behavior ?
The reason behind this : Im using Models that can tell if their last update requires persistent backup by comparing the previous value to the new one.
I would like to listen to the key up event on my form inputs but if I do that, knockout triggers twice event (the default one + the key up) to update the Model and the second one is basically telling my Model to replace the value by the same value because it is already updated, which it translates to "there is no need to do persistent backup since the value didnt change".
I would gladly appreciate any help or suggestion, since Im stuck and can't find a way around :)
EDIT
Couldnt reproduce the error with bare backbone code. It seems as "super cool" said that valueUpdate should override the default Blur event that triggers when you use form controls with binding Value.
It may be a bug introduced by the library Knockback that I use to create the ViewModel.
Despite all this, just replacing the binding Value by the binding textInput did the trick. Thank you all.
Don't listen to the event, subscribe to updates, which won't fire unless the value is changed. Using the textInput binding will register every change to the value, even those done using menu items like cut and paste, when they happen.
Equivalently, you can use the value binding along with valueUpdate: 'input'
vm = {
myvar: ko.observable(),
updates: ko.observableArray()
};
vm.myvar.subscribe(function(newValue) {
vm.updates.push(newValue);
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="textInput: myvar" />
<div data-bind="foreach: updates">
<div data-bind="text: $data"></div>
</div>

Resources