This is perhaps a very silly question.
I am receiving data from an endpoint in the following format. I want to assign the prediction a serial number taking into account the predictions in the previous category.
const items = [{
"category": "Office",
"predictions": [
{
"id": "2599",
"value": "Printer",
"type": "OFF"
},
{
"id": "2853",
"value": "Camera",
"type": "OFF"
},
{
"id": "2202",
"value": "Keyboard",
"type": "OFF"
}
]
},
{
"category": "Home",
"predictions": [
{
"id": "2899",
"value": "Television",
"type": "ELEC"
},
{
"id": "2853",
"value": "Microwave",
"type": "ELEC"
},
{
"id": "2732",
"value": "Washing Machine",
"type": "ELEC"
}
]
}
];
In React, I am doing the following to render the predictions to the customer based on their query:
const [highlighted, setHighlighted] = useState(-1);
// other code
const showPredictions = (predictions, categoryIndex) => {
return (
<ul role="listbox">
{predictions.map((prediction, index) => {
const serialNum = index;
const isHighlighted = highlighted === serialNum;
return (
<li
onMouseEnter={() => handleSuggestionMouseEnter(serialNum)}
className={isHighlighted ? 'highlight' : ''}
>
{prediction.value}
</li>
);
})}
</ul>
);
};
const showPredictionsByCategory = (items) => {
return items.map((category, catIndex) => {
const categoryTitle = renderTitleText(category);
const itemList = showPredictions(category.predictions, catIndex);
return (
<div>
{categoryTitle}
{itemList}
</div>
);
});
};
Expectation:
I want to increment and decrement this serial number so that I can highlight the item on keyup and down. Hence, I want the predictions to be numbered 0, 1, 2, 3,...n ( where n = number of predictions minus 1)
So in the above example, the Office predictions would have serialNum 0, 1, 2 and Home predictions would have serialNum 3, 4, 5 respectively.
The predictions won't always be 3 per category, they can be any number.
Any advice is appreciated.
Based on your comments, the problem you want to solve is:
I'm going to be using three components:
<Categories>to render an array of categories<Category>to render a single category (array of predictions)<Prediction>to render a single prediction.Avoid using the array index as an ID
It's not that it's not possible, it's that it sets you up to run into strange bugs later on. Try and uniquely identify each prediction with an ID property of its own. Do the same with your categories.
For example:
Flatten the hierarchy to make things easier
You need to know which predictions are before and after the currently-selected prediction. Rather than messing about with some convoluted logic involving categories, take them out of the equation entirely!
You can use the built-in JS function
flatMapto flatten your categories so you have a big array of predictions to use for your ordering. Then, use React's built-inuseState()to store the currently-selected index.Tell your child components which prediction is selected
Categoriesis currently the only component with any knowledge of the selection, so we need a way to tell the child components (the ones that render predictions) whether they're selected or not.Pass the ID of the current selection down the chain:
The ID is all you need to identify a single prediction. You don't want to pass
selectedIndex, you needallItemsandcategoriesto make sense of it and there's no point passing all that stuff down.Tell your predictions how to highlight
If you're passing
selectedIddown the chain this is nice and easy. At this point you can change the default selection ID to confirm the right predictions are being selected.Bind the
onKeyUpevent to update the stateBind the
onKeyUpevent on your<div>in<Categories>and wire it up to changeselectedIndex. I've omitted bounds checking for clarity but you definitely want that to avoid going off either end of the array.tabIndex="-1"is needed so that thedivcan receive keyboard events.Putting it all together
Here's a full example, including bounds checking: