ReactDOM.render has no effect in specific circumstances? - javascript

I have a method that renders an icon (font-awesome icon) inside provided container. Icon rendering can happen by user clicking on specific div or by program itself automatically calling rendering function when it mimics user clicking specific div.
To better understand this. I have created this so called TicTacToe game. It is possible to play player vs player or player vs cpu. If two players are playing then there is no problem, everything is rendered fine.
Now when player plays against CPU, something strange happens. If first player is CPU, then its first move is not rendered (icon does not appear). But the rest appears fine.
And if I make both players to be CPU (CPU plays against another CPU), then nothing gets rendered. Could it be that ReactDOM.render ignores changes if they happen too fast?;)
So here is part of the program (game):
$( document ).ready(function() {
const ICONS_CLASSES = {
x: 'fa fa-times fa-lg',
o: 'fa fa-circle-o fa-5x'
}
function renderMove(el, turn){
const classes = ICONS_CLASSES[turn];
ReactDOM.render(
React.createElement('span', {'className': classes}),
el
)
}
...
...
});
Also here is a function that is called by program itself to mimic clicking on a specific div in a game (well let say CPU "clicks" it):
function clickPosition(el, tic){
if(tic.state == 'running'){
// Save which player played, because after playing move, it will
// switch turn for another player.
const type = tic.turn.type;
const res = tic.play(el.id);
if(res != 'invalid')
renderMove(el, type);
updateInfo(tic.info)
// Add start block to be able to play again.
if(tic.state == 'stopped'){
// Highlight win combo if there is any
if(tic.winCombo)
highlightWin(tic.winCombo)
toggleEl($('#start'))
}
}
}
So calling such render as previously said will not render all the time (when playing with CPU).
But if I change that render to this:
el.innerHTML = `<span class="${classes}"></span>`;
Then it renders any icon just fine. No matter if game is played player vs player, cpu vs player, player vs cpu or even cpu vs cpu (in this case all icons are rendered instantly, because the end result is always draw).
Is there some gotcha with ReactDOM.render?
P.S. If you are interested, you can find full code here (currently it is enabled to be played cpu vs player, meaning first will play CPU. And because it is rendering with ReactDOM.render, first move will be invisible. Others should appear fine): https://codepen.io/andriusl/pen/qjyBdB

It looks like everything is OK with ReactDOM.render. But I was kind of right with guess about rendering happening too fast. But from another place.
There was a function (that I haven't mentioned in question) which cleared all rendered icons. And it would clear after starting the game. When players are playing, then there is no problem, because clearing does happen later then user clicks a div. But when cpu does that, it does much faster, so it plays its turn before clearing up is called and it clears that move icon.
So technically it is rendered, but it is instantly removed, looking like it was never rendered, at least to us humans:)
So fix was to move ReactDOM.unmountComponentAtNode before tic.start. Then it always clears before starting game, not after (or before starting another game).
$('#x, #o').on('click', function() {
const second = {'x': 'o', 'o': 'x'};
// Clear filled positions if any.
let positions = document.getElementsByClassName('pos');
_.each(positions, pos => {
ReactDOM.unmountComponentAtNode(pos);
})
tic.start(this.id, second[this.id]);
toggleEl($('#start'));
updateInfo(tic.info);
})

Related

How to stop a Phaser game and remove it from a page?

I have a single webpage that I want to be able to run three JavaScript games, sequentially. I start one with
//jQuery to start a game
$(document).ready(() => {
//When the logo image is clicked
$("#logo").click(() => {
//Get the archery game
$.getScript('archery.js', () => {
//Start it
startArchGame();
//Remove the image from the HTML doc
$("#logo").remove();
});
})
})
Then, inside archery.js, once a condition is met, the following code is executed
$.getScript('skateboarding.js', () => {
startSkateGame();
});
game.destroy();
The game.destroy(); stops the game from running in Phaser 3, but the next game is just loaded below the first one, so you can't see it. How can I fix this? Is it possible to delete the first script I got entirely?
I was able to solve this issue within the Phaser framework.
I changed game.destroy() to game.destroy(true, false).
The first argument of the destroy method, true, says that I want to remove the game from the canvas element of the page when I destroy the game. The second argument, false, says to NOT remove all of Phaser and its plugins for the page. I set this to false because I want to create another game in Phaser on the page after I destroy my first one.

How to deal with over 100 moving rectangles without lag

I have this fiddle : https://jsfiddle.net/reko91/e6uwqnof/2/
On button press it creates 50 rectangles that all move down towards the bottom of the screen.
for(i=0;i<50;i++){
enemyArray.push(new enemy(normalBullet.x+i*5, normalBullet.y, normalBullet.speed, 1, 10, "#F00"));
}
Works fine on first click, but once I start adding more, it really starts to lag. Is there a best of practice way of dealing with hundreds of moving elements ? Or is HTML and Javascript not the best language to deal with this amount of moving data ?
Your main problem is in the update function:
function update() {
// enemy.update();
//if (keystate[SpaceBar]) {
$('#newEnemy').click(function() {
createNewEnemy()
})
//...
}
Probably a mistake, but you're attaching the event every time update gets called, which is 60 times per seconds! (Until it can't do it anymore, that is.)
This means that every time you press the button, you generate a ton of elements right in the canvas.
Move the event listener addition outsite update and you're golden.
You are assigning button pushes inside the frame loop, so when you push it, it's actually calling the button push however many times the loop has run.
Move this code outside:
$('#newEnemy').click(function() {
console.log("createEnemy");
createNewEnemy()
});

SVG 4 Everybody freezes left and right click

I'm using the svg4everybody and I don't understand why sometimes it freezes the mouse interacions.
The plugin is loaded in many iframes dynamically, but only some times it freezes.
If I hover on buttons and other clickable elements the cursor changes and if i press the back button the site goes back and the freeze disappear.
Looking in the source file I see that the requestAnimationFrame function is used:
function onframe() {
var use;
while ((use = uses[0])) {
// some code
}
requestAnimationFrame(onframe);
}
if (IE9TO11) { // <-- edited in tests with if ( true || IE9TO11 )
onframe();
}
It is possible that it's the requestAnimationFrame that make the freeze? Or someone has another better idea?
NOTE: it freezes only in IE11. Tried in FF32 and Chrome 39 and works without problems

Javascript glitchy game

I have a game and when you hit the Obs's you get a game over screen. On it has a retry button and it resets it, it works most of the time but after the third or fourth retry it does not reset it. It just keeps it where it is. Why does it do that? Below is the code I used for the reset and a link. Thanks.
if (collides($(value), $('#player'))) {
$('#levelOne').stop();
$('#player').css('border', 'solid 1px yellow');
//GAME OVER SCREEN START
$('#GameOver').fadeIn();
$('#retry').click(function () {
$('#GameOver').fadeOut();
// NEW LOGIC
$("#levelOne").css('margin-top', '-1520px');
$("#player").css('border', 'solid 1px green')
$("#player").css('margin-left', '223px');
$('#levelComplete').hide();
$('#levelOne').animate({
'margin-top': '+=1520px'
}, speed);
handleCollisions()
});
}
http://jsfiddle.net/38bod36e/101/
You are constantly adding click event listeners in the handleCollisions function (this part: $('#retry').click(function () {), which is bound to kill your performance sooner or later because the number of events created/called will get insanely big. That is something you need to take care of to get rid of the glitches.
I moved the click handler function outside and it works just fine. I've also disabled the console log on every frame because it kills the performance as well.
See it here: http://jsfiddle.net/38bod36e/103/
Be careful with stuff like that if you want a consistent performance. See in the console how the number of events grows with every frame rendered in your original code: http://jsfiddle.net/38bod36e/105/

setTimeout increases everytime it is cleared and called again

This is one of the stranger things I have come across.
http://cabbibo.com
Basically, on my site, there are a bunch of spinning shapes. Each spinning shape sets a timeout when it is first called, to make it spin. Whenever a visitor clicks on the webpage, these shapes are cleared and randomly generated again.
The problem is that on the second click they are spinning a bit faster. on the third click even faster, and by the fourth click they are spinning so fast that they get super choppy and unfluid.
When watching the site with the chrome://flags FPS counter, it will start at an EVEN 60 fps, and then by the time it gets to the fourth or fifth click, it will be jumping between 20 and 50 fps.
an abbreviated section of the code is as follows:
//creates timeout variable OUTSIDE the timeout function, so it can be cleared
var t;
var speedRandom;
function getRandSpeed(){
var randomSpeed = (Math.random()*.01);
if (randomSpeed<=.001){
randomSpeed=.001;
}else if(randomSpeed>=.005){
randomSpeed=.005;
}
console.log(randomSpeed);
if (rightSpin==0){
speedRandom=randomSpeed;
rightSpin=1;
}else{
speedRandom=-randomSpeed;
rightSpin=0;
}
}
objs[whichImg].speed = speedRandom;
function rotateDrawing(whichImg){
//This is the function that centers the object
centerImg(whichImg);
//translates the object to the centered point (different for each frame)
objs[whichImg].ctx.translate(objs[whichImg].centeredX,objs[whichImg].centeredY);
//rotates to the correct angle
objs[whichImg].ctx.rotate(objs[whichImg].angle);
//draws the image
objs[whichImg].ctx.drawImage(objs[whichImg].image,0,0,objs[whichImg].height,objs[whichImg].width);
//adds to the angle of the object
objs[whichImg].angle+=objs[whichImg].speed;
t=setTimeout(function(){rotateDrawing(whichImg)},40);
}
//THE ABOVE CODE WILL BE EXECUTED FOR EVERY SHAPE (TOTAL AROUND 5)
//this is what is called when the screen is clicked
function destroy(){
functionThatClearsAllTheImages();
clearTimeout(t);
rotateDrawing(whichImg);
}
This code may have some holes in it, but it does function, the problem is that after the fifth click it is choppy.
I can add more code if anybody needs it, but any suggestions would be extraordinarily helpful!
The Problem was that each time I created a new object, the timeout lay within that creation code. This meant that the timeout was called 5 times, and when I cleared it, it was only cleared once.
In order to solve the problem, I created one timeout function that contained a loop within it that would rotate the shapes. This meant that everytime I had to clear it, it would essential clear the loop for all 5 shapes!

Categories