In react, setting state's value with the equal old's one is guaranteed not triggering render, right?
How about storing an array in state?
React compares the array by reference, not by values deeply.
So setting a new array with exactly the same values still triggering render.
I created a component that listening a scroll event.
Thus I need to use useEffect to attach & detach the scroll event.
On every scroll event, it determines which children are visible within scroll view,
and save the indices (an array of index) of the children into a state, something like this:
const [index, setIndex] = useState(-1);
const [indices, setIndices] = useState([]);
/* ... */
useEffect(() => {
const handleScroll = () => {
const newIndex : number = calculateFirstVisibleChild();
const newIndices: number[] = calculateVisibleChildren();
// save the result:
setIndex(newIndex); // trigger render only if the value changes (works)
setIndices(newIndices); // always trigger render (works but inefficient)
}
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll); // cleanup
}, []); // no dep, execute once at startup
The problem are:
How to set the indices with the same values without triggering the render.
If the scrolling distance is small, the visible children is remain the same, so the function still returning the same values.
I cannot comparing the indices & newIndices before passing into setIndices because it needs to be listed on the useEffect's dependencies, thus causing the event listener detached & attached back unnecessarily every index/indices changes.
Here the screenshot of the component i'm trying to make:

Update: here the usage of the stored index/indices:
At this moment i use the index (single level).
I'm going to upgrade my NavScroll to multi level after the indices problem solved.
// the render:
.....map((child, i) => (
<ListGroupItem
key={i}
active={(i === index)} // here the actual highlight works! true: highlight, false: normal
>
</ListGroupItem>
.....
Update:
I will convert the indices array into comma separated string to avoid triggering unnecessary render and parse/convert back to array when render.
I know this is an ugly hack, but it works.
Please help me solving with the beauty way.