Reputation: 726
I am making a very simple ReactJS/Gatsby website for someone and I am having an issue with one of my functional styled components when it re-renders. The problem is that it is causing the window to jump (scroll) after the re-render is complete.
The re-render is triggered by the user clicking on a span element (enclosed in an li
element) which fires a function.
The list of li
elements is determined by the state of the component. The overall parent component has a fixed height which is why I am having trouble diagnosing the issue.
What I Expect to Happen
The component to re-render and the window's scroll position to remain where it was when the user initiated it.
What Actually Happens
When the user clicks the element the page appears to jump (scroll). Sometimes it does so and remains in the new position, sometimes it does so and then returns to the original scroll position.
I've tried following advice from other questions which suggest using event.preventDefault()
and others which suggest moving the styling out of the component itself and, instead, opting for using classes.
Neither of these solutions worked.
I have managed to definitively find that the issue is due to setActiveTabs -- which causes the re-render of the ul
element -- as logging window.scrollY
both prior to it firing and after it completes displays a different value.
I have managed to figure out that the issue is with making the list items targetable. It seems that either adding the tabIndex="0"
attribute or making the li
child an interactive element causes this bug.
Does anyone know a way around this?
The full frontend source code can be found in the following GitHub repo: https://github.com/MakingStuffs/resinfusion
Upvotes: 1
Views: 1724
Reputation: 726
In order to solve the issue I needed to prevent the clicked element from being targeted on the re-render. In order to do this I edited the clickHandler so that it uses element.blur()
after setting the state.
The click handler is as follows:
const forwardClickHandler = event => {
setLoading(true)
const clickedSlug =
event.target.closest("button") !== null
? event.target.closest("button").getAttribute("data-slug")
: event.target.children[0].getAttribute("data-slug")
const categoryObject = getNeedle(clickedSlug, categories, "slug")
const subCatObject = getNeedle(clickedSlug, subCategories, "slug")
const serviceObject = getNeedle(clickedSlug, services, "slug")
const associatedChildren = getAssociatedChildren(
categoryObject
? categoryObject
: subCatObject
? subCatObject
: serviceObject
)
setBgImage(associatedChildren[0].thumb.localFile.childImageSharp.fluid)
setActiveTabs(associatedChildren)
event.target.blur()
return setTimeout(() => setLoading(false), 1000)
}
Upvotes: 1