What to do with components that re-render frequently?
What I'm trying to do is to have a value entered in a TextInput and have that value exposed in multiple squares (Views).
For example, if I type 12345, it will appear in the view as [1][2][3][4][5].
However, we'll draw 5 views initially, and if the input is longer than 5 characters, we'll draw 5 new views and keep repeating.
data = "12345".split("");
data.map(item => <View>{item}</View>
and touch a view to move the cursor to that location to continue typing. For example, if you touch [3] and then type a, it will look like [1][2][3][a][4][5].
As a result, the app is slowing down as all those views are re-rendered, resulting in the error below.
Please report: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code
It's hard to use memo because it keeps re-rendering (because it changes the values inside the view).
What can I do to fix this?
Related
Refering to a live javascript playground at https://codepen.io/Maximusssssu/pen/MWrzpav?editors=1011 .When you click on the grid, it will put a triangle or a square depending on your liking using the buttons (triangle & square below the grid). However, I am trying to build an Undo function for both triangle and square. Can anyone offer me some guidance on this? Thank you for reading and have a nice day :) I use the code below to put square or triangle on the grid.
newDot.style.top = y + 'px';
newDot.style.left = x + 'px';
// Add the new element to the end of the body:
document.body.appendChild(newDot);
I would use Memento pattern to implement the undo functionality with the classes listed below.
Basically, the client (main function in my example) invokes const s = Grid.snapshot() method to take a snapshot of the current state of the Grid, and invokes History.push(s) to save the snapshot. When the client needs to undo the change, it retrieves the previous grid state, i.e. snapshot, by invoking const pre = History.pop(), and then feed the previous snapshot to the grid by Grid.restore(pre). The Grid.restore() method can internally invoke Grid.render() method to render the previous state of the grid, i.e. draw the previous set of dots.
Grid Class
Grid holds information about the grid, i.e. all the coordinates of the dots, shapes of the dots, etc.
Snapshot Class
Snapshot captures the state of the grid at some point in the past. Grid is responsible for producing an instance of Snapshot.
History Class
History saves all the previous states of the Grid by storing Snapshot objects. It it essentially a "stack", so it can push or pop a snapshot in a LIFO manner.
main
main function handle all the above objects to realize the required functionalities of the app.
UML Diagram
In order to implement the undo functionality separately for the square and triangle dots, I would tweak this design in such a way that it keeps track of two sets of previous states, one being the triangles and the other being squares. This would result in having two History objects, one recording previous states of square dots and the other recording those of triangle dots, as well as the Grid object producing separate snapshots for squares and triangles.
I have data which updates every 10 seconds and I would like to check that all the data is valid before progressing with updates. I am currently getting false data intermittently which occurs as a negative number in one of the values. If one of the objects has a negative value then I don't trust the whole set and don't want to update any elements.
Ideally I don't want to update some items and then bail once the incorrect value occurs, but rather, determine if the whole set is good before updating anything
I'm not sure how d3 can manage this but I've tried with this and it seems to work. But it doesn't seem particularly in keeping with the elegance of D3 so I think there's probably a correct and better way to do it. But maybe not?!
var dataValid = true;
abcItems.each(function (d, i) {
if (0 > dd.Number1 - dd.Number2) dataValid = false;
});
if (dataValid) {
abcItems.each(function (d, i) {
// updating elements here
});
} else {
console.log("negative value occurred");
}
Is there a better way to manage this through D3?
A little bit more context:
The data (JSON provided via a RESTful API) and visualisation (a bar chart) are updating every 10 seconds. The glitch in the API results in incorrect data once every hour or so at the most (sometimes it doesn't happen all day). The effect of the glitch is that the bars all change dramatically whereas the data should only change by ones or twos each iteration. In the next fetch of data 10 seconds later the data is fine and the visualisation comes right.
The data itself is always "well-formed" it's just that the values provided are incorrect. Therefore even during the glitch it is safe to bind the data to elements.
What I want to do, is skip the entire iteration and update phase if the data contains one of these negative values.
Perhaps also worth noting is that the items in the data are always the same, that is to say the only "enter" phase that occurs is on page load and there are no items that exit (though I do include these operations to capture any unexpected fluctuations in the data). The values for these items do change though.
Looking at your code it seams you already have bound the dataset to your DOM elements abcItems.each(...).
Why not bail out of the update function when the data is not valid.
d3.json("bar-tooltip.json", function(dataset) {
if (!dataset.every(d => d.Number2 <= d.Number1)) return;
// do the update of the graph
});
The example assumes you call d3.json() froma function that is called every update interval, but you can use a different update method.
I am working on a project dealing with sensor data. In my backend everything is stored in a database which is getting polled by a controller and converted into kml to display on the cesium globe. This poll happens every 5-10 seconds and contains around 4000-8000 objects (we store up to 1 minute worth of data so we are looking at somewhere like 20k - 50k points). Following this I have an update function which slowly fades the markers out which updates every 5 seconds.
To load the kml on the map I use the following function:
var dataSource = new Cesium.KmlDataSource();
dataSource.load('link').then(function(value);
viewer.dataSources.add(dataSource);
});
On the update color function I am iterating over all of the objects within the datasources entity collection and updating them like so (this is very inefficient):
var colorUpdate = Cesium.Color.fromAlpha(newColor, .4);
dataSource.entities.values[i].billboard.color = colorUpdate;
When I do and add or color update I see a large amount of lag and was curious if there was anything you would suggest to fix this? Generally I get a freeze up for a few seconds. After 60 seconds of the data being on the map it gets removed like so (just a different if case within the color update loop)
dataSource.entities.remove(dataSource.entities.values[i]);
Is there potentially a way to set a propertiy for an entire entity collection so when this collection becomes 30 seconds old it updates the color to a new one? It seems that I just need to find a way to set a property for the entire collection vs individual entities. Does anyone know how to do that or have a suggestion for something better?
I'm using window.DeviceOrientationEvent to listen for changes in the device orientation. However, I want to calibrate my application to report orientation changes relative to the original orientation. In order to do this I have come up with the following solution:
originalOrientation.freeze = false;
window.addEventListener('deviceorientation', function(e){
var orientation = {g: Math.round(e.gamma), b: Math.round(e.beta), a: Math.round(e.alpha), o: window.orientation || 0};
if(!originalOrientation.freeze){
originalOrientation = orientation;
originalOrientation.freeze = true;
}
});
This essentially takes the first value returned by the deviceorientation listener and "freezes" it so it doesn't keep updating. I don't like this method because I'd rather do the calibration elsewhere in my code, instead of the place where the actual orientation is gathered. I also don't want to attach the listener twice because the value returned in the callback will be lost.
TLDR;
Is there a way I can call something like window.getDeviceOrientation() to return the alpha, beta, and gamma values synchronously instead of attaching a callback?
I think the full-tilt library would achieve this for you.
There's a simple example on the github page that shows how you initialise their promises based library, then in your logic, you just check that the device orientation object exists (IE the promise was fulfilled) before calling a method such as deviceOrientation.getScreenAdjustedEuler().
You don't have to be using an animation loop like in their example.
As an aside, you could have added and removed the event listeners without losing your data. I definitely would have done that rather than disable the listener with the freeze. I was adding and removing listeners as required for a while to get the initial state to compare with later when constant updates were needed (or more accurately not subscribing to the event when they weren't needed). I'd still go with full-tilt though. I used it because it provides normalised data across devices but it does pretty much what you want and would probably make your code a little neater.
If you're still working on it 5 months later that is, yeah this is probably of more use to someone hunting around now.
I have some nested React components, the inner of which is a large svg graph with hundreds if not thousands line and rect elements. To enable some application-wide behaviour and appearance changes I thought to change the className of the uppermost component. The problem is, that the whole application re-renders if I do that.
I understand that this behaviour is somewhat intended, in the sense of a unidirectional render flow, but I thought React would be smarter about what it can reuse and keep DOM changes to a minimum.
Minimal example here: https://jsbin.com/rabofewawu/1/edit?html,js,output
As you can see, the line pattern in the SVG changes every time you press 'here' though I only want the background color to change.
A similar, but more extreme, example arises when I try to zoom and pan the svg by changing the transform property of an inner g element. Using d3, I simply change the attribute. With react, my render function gets called, the updated state results in an updated transform property, and the whole group is re-renderd from scratch instead of changing the DOM attribute.
Am I missing something? Whats the React way to achieve what I'm trying to do?
Take this simple harmless looking render function:
render(){
return <div>{Date.now()}</div>;
}
In React's mental model this would always display the current number every millisecond. React conceptually updates infinite times per second. The inputs of render here are everything in the world, but we happen to just use the clock. Given the same world, we get the same output from render and thus it's idempotent.
Well crap... we don't have infinitely fast computers so we need to compromise. Instead of render's input being everything we restrict it to state and props (and context).
In this restricted setting use of Math.random or Date.now breaks the rules. If you need to use the output of these, it must go through state or props first. How would this look? Well we can use a deterministic random number generator and store the seed in state. Here's a modified version of your component doing that:
var MyComponent = React.createClass({
displayName:"MyComponent",
getInitialState(){
return {
seed: Math.floor(Math.random()*0xffffff)
};
},
render: function() {
// make a random number generator with the given seed
var rng = new Chance(this.state.seed);
function random(x){
return rng.floating({min: 0, max: x, fixed: 7})
}
var s=100, lines = [];
for (var i=0; i<100; i++) {
var line = { x1: random(s), y1: random(s), x2: random(s), y2: random(s) };
lines.push(React.createElement("line", line));
}
return React.createElement("svg", { height: s, width: s}, lines);
}
});
Rendering less than infinite times per second, and rendering only certain components is an optimization. Optimizations should not affect the behavior of the program.
If you wanted different random numbers, you could set the seed to a different random number. Using real Math.random() here is okay because state is the result or i/o operations in your code, and you're invoking this setState in response to some other i/o (e.g. a click handler).
Time is similar; if you want the current time to be rendered, use a setTimeout and setState with the current time. You can then display it how you like in render, including passing it down to other components and doing any kind of math on it you like.
You can control this with the component's shouldComponentUpdate function. By default this always returns true (so the component will always re-render).
There's a little bit of documentation for this function here https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate