Reputation: 145
Why isn't this working as expected? Sometimes it works, and sometimes it doesn't - i cannot figure this one out. The piece of code with ScrollIntoView
was copied from another js file with another page, and in that one it works just fine?
The ID's refTP
and refPP
are found within div tags in ReferencesPP
and ReferencesTP
import React, {useState} from 'react'
import ReferencesPP from './referencesPP'
import ReferencesTP from './referencesTP'
import "./references.css"
function ReferencesPage(){
const reftp = document.getElementById("refTP");
const refpp = document.getElementById("refPP");
const [page, setPage] = useState(false);
const handleClick = (id) => {
if(id === 0 && page===true){
reftp.scrollIntoView({ behavior: "smooth" });
setPage(false);
} else if(id === 1 && page===false){
refpp.scrollIntoView({ behavior: "smooth" });
setPage(true);
}
}
return(
<div className="references-main-container">
<ul>
<li id="anchor1" onClick={()=>handleClick(0)}></li>
<li id="anchor2"onClick={()=>handleClick(1)}></li>
</ul>
<ReferencesTP />
<ReferencesPP />
</div>
)
}
export default ReferencesPage
Upvotes: 5
Views: 38951
Reputation: 1
faced the same issue, what worked for me was using scrollIntoView in the callback of a setTimeout with a delay of 1 sec(or less maybe)
useEffect(() => {
setTimeout(() => divRef.current.scrollIntoView({ behavior: 'smooth' }), 1000);
});
Upvotes: 0
Reputation: 2885
It does not work initially because by the time your component function run there is no elements yet. And it works if there were some sequential renders, since at that time there is some elements. However, it is still wrong way to do this. Accessing DOM from react should be considered side effect and you can't have side effects in pure functions (and your component is pure function.
In functional react components you can tackle side effects in few ways. One of this ways (and often is the best way) is hooks. If you want to store some mutable data (as DOM element) it is good to use useRef
hook. This way React will set ref to DOM element and it can be passed by reference into your event handler. You still will need to check if element is actually exists, but with getElementById
you should do the same.
I made small fiddle for you to look, how you can use refs for your case.
Upvotes: 8
Reputation: 13078
The first time this lines are evaluated to null
because the components have not been rendered yet:
const reftp = document.getElementById("refTP");
const refpp = document.getElementById("refPP");
Move the element reference to handleClick
function:
const handleClick = (id) => {
const reftp = document.getElementById("refTP");
const refpp = document.getElementById("refPP");
if(id === 0 && page===true){
reftp.scrollIntoView({ behavior: "smooth" });
setPage(false);
} else if(id === 1 && page===false){
refpp.scrollIntoView({ behavior: "smooth" });
setPage(true);
}
}
Upvotes: 2