Cannot read property 'scrollIntoView' of null
Solution 1
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.
Solution 2
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);
}
}
Related videos on Youtube
Emil Woxen
Updated on May 30, 2022Comments
-
Emil Woxen almost 2 years
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'srefTP
andrefPP
are found within div tags inReferencesPP
andReferencesTP
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
-
Emil Woxen about 3 yearsI did not know this - so thanks a bunch! How would one go about fetching the ref from another component? Like the way i use
.getElementById
in the code above? -
Emil Woxen about 3 yearsNevermind - thanks a bunch, i found out. One question, what does
if(!ref.current) return;
do exactly? -
Mr. Hedgehog about 3 yearsSince it is a mutation on value, you can't be sure that you have value you want on ref. This is just a precaution that value will be there when you will try to access it. Otherwise it will just exit function without doing anything and without raising an error. You can otherwise use try/catch to handle such error, or if you have 200% confidence in your code and react code and anything in between, you can omit said precautions. I try not to trust myself too much and check, just to be sure.
-
Mr. Hedgehog about 3 yearsJust in case, someone will be reading this in the future, I'll answer about refs on child components. It can be achieved with ref forwarding.