my reactjs button design feels slow onTouch on tablet vs tablet buttons - javascript

I built a web app that is viewed on tablets. It was made with reactjs and a express backend. It's a relatively small app that simple in that it just display items and allows users to customizer order items and such.
This was my attempt to create a custom 'check box' style button.
I have an array of items var items = ['ab','bc','cd','de','ef','fg','gh','hi','ij'] that can at times have about 30 elements total.
I create another array to list my items by pushing each elements in as li blocks
var itemsList = ;
items.forEach(item => {
toppingsList.push (
<li className={(this.checkChosen(item) === item) ? 'itemChosen' : 'itemNotChosen'} onClick={(e)=>{this.handleItemClicked(item)}}><p>{item}</p></li>
)
})
From here I create those <li></li> where checkChosen(item) checks if the topping is inside the 'selected pile'. The handleItemClicked(item) pushed an item into this components state.
this.state = {
itemsChosen = [];
}
It also checks to see if it's within the itemsChosen state and either adds or removes it.
I run this on a Lenovo tab 10 on a local host and it seems like these buttons have a delay, as if the onClick isn't very responsive. I used a similar method for a pin pad design.
I thought this could be an issue with the tablet but when I invoke the native keyboard for the pin pad (just an input type = "number" ) it feels quick, and smooth how you would expect the web app to run.
This method doesn't seem to be very demanding, but is it?

Related

Is there a way to run this script in a sequence?

For context I've made a script to assign a localstorage item based on what the user selects, this item may contain "S10" but could also contain many other values, for this example the user has selected "S10"
This has now stored into localstorage.
I have created this script that I have placed in each of the product grid includes, so this script will load multiple times for each product:
window.onload = function() {
const string = localStorage.getItem('MyfitmentList', JSON.stringify(myfitment) );
const attr = {{ product.metafields['fitment']['fitment'] | json }};
document.getElementById("fitment").innerHTML = (`${string.includes(attr) ? '✔' : 'not a fit' }`);
}
Each product grid also features this container <div id="fitment"></div>
The script above loads individually for each product grid card and has it's own seperate values for "attr". If "attr" doesn't contain "S10" (which the user previously selected) then it should show "not a fit", but if the product does contain "S10" then it should show the tick.
The problem I'm having is that this only works for the first script, on the first <div id="fitment"></div> container. I can see that each individual script has a different "attr" value which is good, but I don't know why only the first container is populated.
Each script should run individually and populate the "fitment" container within it's own product card. I'm a bit at a loss as to how to do it.
Also this is on Shopify - Someone below has recommended using a single script with a loop, but in that case how would I retrieve a unique "attr" value each time the script loops? this would still leave the question of how to populate each fitment container with the correct message for each product.
Any help would be really appreciated!

How to create a snappy User Interface with lots of local data?

I have a JSON file with 15000+ items. My JSON file has about 7MB. I'd like to display all results in a table (without pagination) and add a few checkboxes to display or hide the items under certain conditions. To simplify as much as possible, let's say I have a checkbox to display items from Paris only:
The problem is that the UI is not smooth. Clicking on the checkbox takes about one second to refresh the table. It's unacceptable.
I'm using fetch() to download JSON data and then keep it locally. When user clicks on the checkbox, here's what I did:
document.getElementById('paris-only').addEventListener('click', updateTable);
function updateTable() {
const parisOnly = document.getElementById('paris-only').checked;
items.forEach(item => item.visible = !parisOnly || item.city === 'Paris');
refreshTable();
}
function refreshTable() {
[...document.getElementById('items-table').children].forEach((tr, index) => {
tr.classList.toggle('hidden', !items[index].visible);
});
}
.hidden {
display: none;
}
I tried to play with setTimeout(_, 0), but it doesn't help much. It makes the UI freeze less, but it still takes a lot of time to refresh the table.
Is there any strategy available to make such an interface snappy? One of my ideas was to consider <canvas>, which makes drawing many elements quick, but it doesn't seem very natural for the task.
Another option would be to load data with fetch() on scroll, but I'd like to have all data loaded just once if possible.
What else should I consider?
I'd recommend using classes to signify if a given node should be shown or hidden (e.g. every node with name !== 'Paris' is in the notparis class. You can use javascript to initialize these categories (How do I add a class to a given element?) when you fetch the JSON table, and then showing/hiding can use for (tr of document.getElementsByClassName('notparis')) tr.visible = !parisOnly. If these categories overlap (i.e. you want notparis and notcoldweather), you could probably record which classes are currently visible or hidden and use document.getElementsByClassName('notparis notcoldweather') (this may be a bit more complex, but should maintain performance).
Also, changing the items directly instead of using an intermediate list might be more performant.

Where to handle parent-child event React

I'm getting start with React basic concepts, and I'm not sure how to proceed...
I'm trying to build a simple Minesweeper game, my structure is a MinesweeperField wrapper, with height, width and minesNumber as props, and a MinesweeperTile, with value (is it a mine/number of close mines) and explored as props.
My problem is, I'm not sure how to handle clicking on the tiles. The MinesweeperField component must be notified when a tile is explored to handle the new game state (ex: in case of game over or win), and it must also be able to trigger explore in other tiles (for example, if you click on a tile with 0 close mines, all of the adjacent tiles must be explored automatically).
From what I understood there are two approaches:
Handle click on the Tile, Tile notifies Field, Field triggers explore also on adjacent Tiles - notifying Field from Tile is easy, but calling Tile from Field would require to use refs, plus a different click handler function is instantiated for each Tile
Handle click on Field, Field updates the prop that in render is used to assign the isExplored prop to the Tile - since I render the Tile based on an array variable in the Field's state, I have to use setState to trigger a redraw of child Tiles components.
this is a simplified sample of the render function, in the "Handle Click on Field" version:
return (
<div className="minesweeper-wrapper">
<div className="minesweeper-field" style={this.getDimensions()}>
{this.state.proximityMap.map(function(verticalRow, vIndex){
return verticalRow.map(function(tileValue, hIndex){
return <MinesweeperTile value={tileValue} hIndex={hIndex} vIndex={vIndex} onClick={this.exploreTile.bind(this, vIndex, hIndex, tileValue)} isExplored={this.state.explorationMap[vIndex][hIndex]} />
});
})}
</div>
</div>
);
and here's the exploreTile function:
exploreTile(vIndex, hIndex, tileValue) {
this.unveilTile(vIndex, hIndex);
if (tileValue < 0) {
this.gameOver();
} else {
if (tileValue === 0) {
this.propagateTileExplore(vIndex, hIndex);
}
}
}
this.state.proximityMap contains values indicating how many mines are close to this tile/is this tile a mine. this.state.explorationMap contains bools indicating which tiles have been explored.
My problem with this approach is that, from what I understood, if I want to redraw a single tile, I have to call setState on Field and update this.state.explorationMap array, which will redraw every tile!
Any ideas as to how I could limit the redraw to a single Tile? Should I keep exploring the "handle click on Field" way or go back to "handle click on Tile"?
I started with "handle click on Tile" but I stopped when I got to the "explore adjacent tiles" problem.
Also please no jQuery/js tricks or hacks to solve this in an unconventional way, it's not about finding a way to do this, but finding the most appropriate. It won't probably make a noticeable difference in the context of a Minesweeper game, but as I said, it's for training purposes :)
The most appropriate way would be to let the parent handle the changes. The children just need to know whom to call when they are clicked and how they should look like. I did the same thing in my Game of Life clone using React.
CodePen Link
changeTile(row, col) {
if (!this.state.isPlaying) {
const newTile = this.state.board[row][col] === 1 ? 0 : 1;
const newRow = [...this.state.board[row]];
newRow.splice(col, 1, newTile);
const newBoard = [...this.state.board];
newBoard.splice(row, 1, newRow);
this.setState({
board: newBoard
});
}
}

Dashcode mobile web app dynamic list row labeling

I'm trying to put together a mobile web app using Apple's Dashcode.
I would like to use a Rounded Rectangle List as a menu interface for my users, however, I cannot seem to change the various rows' labels in a dynamic list.
Here is the javascript for my list:
var dayController = {
/* categoryList will display these items */
_rowData: ["iPods", "Macs", "Applications"],
/* categoryListController must implement the numberOfRows and prepareRow functions */
/* This method is used to find out how many rows should be in the list */
numberOfRows: function() {
return this._rowData.length;
},
/* categoryList calls this method once for every row. */
prepareRow: function(rowElement, rowIndex, templateElements) {
/*
templateElements contains references to all elements that have an id in the category template row.
We use the lines below to update the list with each category item in _rowData.
*/
if (templateElements.categoryLabel) {
templateElements.categoryLabel.innerText = this._rowData[rowIndex];
}
/* Assign an onclick handler that will cause the browser to go a page
showing all products related to this category item, when clicked
*/
var self = this;
var handler = function() {
/* Get the category item associated with this row */
var category = self._rowData[rowIndex];
};
rowElement.onclick = handler;
}
};
I want to be able to assign the rowData[] as the labels for the rows in the lists, but I can't seem to get it to work.
I'm guessing I need to change something with the prepareRow function, right?
Has anyone successfully used JQuery with Dashcode to build a web app? Perhaps that would be a better approach.
Erm wouldn't you set the rounded rectangle in the css and not the javascript?
You can use Dashcode to make the web app but there other alternatives, rather a lot these days actually. However there was a JS framework called JQTouch, built on top of JQuery for doing this. JQTouch has now beed subsumed into Extjs and all of it rename Sechcha Touch. I would suggestyou go an look at that as a more flexible alternative.
I found Dashcode excellent for building Mac Widgets but much more limited for web based iPxx apps.

Ext JS removeAll(false) behaviour

I have been using the following snippet of code in my app to drive a menu that contains different trees depending upon what is selected. It tries to create tree panels only once and to then reuse them if they are selected again, i.e. to keep the trees expanded state.
var west = Ext.getCmp("west-panel");
west.removeAll(false);
west.doLayout();
var existingPanel = Ext.getCmp('component-tree-project-' + systemId);
if (existingPanel) {
west.add(existingPanel);
west.doLayout();
return;
}
//... code to add create and add a new tree panel
The problem is with west.removeAll(false), the false stops the nodes getting destroyed but they do not appear back in the panel. The panel sticks to showing what it last had in it.
Using west.removeAll(true) works fine except for the fact that new panels are always created.
Should not statement be west.removeAll(true);

Categories

Resources