0

I am receiving the error Uncaught TypeError: Cannot read properties of null (reading 'scrollIntoView') when trying to click on an item on my Navbar.

It's bit of a tricky issue, but if I load the page from scratch, it will throw the above error. However, if I save the project in VSCode again, it will work perfectly fine until I refresh the page. Is there anyway to correct this issue?

Navbar.jsx:

import { useState } from 'react';
import { Link } from 'react-router-dom';
import '../App.css';
import myAvatar from '../images/avataaars.png';

function Navbar() {
    const aboutPage = document.getElementById('about');
    const home = document.getElementById('home');
    const skills = document.getElementById('skills');
    const [navbar, setNavbar] = useState(true);

    const handleNavbarToggle = (e) =>{
        setNavbar(!navbar);
    }

    return(
        <>
        <div className='navbar-container'>
            <Link to='/'><img src={myAvatar} className='nav-logo'/></Link>
            <ul>
                <li onClick={() =>{home.scrollIntoView({behavior: 'smooth'})}}>Home</li>
                <li onClick={() =>{aboutPage.scrollIntoView({behavior: 'smooth'})}}>About</li>
                <li onClick={() => {skills.scrollIntoView({behavior: 'smooth'})}}>Skills</li>
                <li>Projects</li>
                <li id='navbar-login-btn'>Login</li>
            </ul>
            <div className={`navbar-toggle ${navbar ? '' : 'open'}`} onClick={handleNavbarToggle}>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </div>
        <div className={`navbar-header ${navbar ? 'navbar-header-hide' : ''}`}>
            <ul>
                <Link className='navbar-header-item' to='/'>Home</Link>
                <Link className='navbar-header-item' to='/about'>About</Link>
                <Link className='navbar-header-item' to='/skills'>Skills</Link>
                <Link className='navbar-header-item' to='/projects'>Projects</Link>
                <Link className='navbar-header-item' to='/login'>Login</Link>
            </ul>
        </div>
        </>
    )
}


export default Navbar;

App.js:

import { useState, useEffect } from 'react';
import { Route, Routes } from 'react-router-dom';
import TextTransition, { presets } from 'react-text-transition';
import './App.css';
import Navbar from './components/Navbar';
import Homepage from './components/Homepage';
import About from './components/About';
import Skills from './components/Skills';
import myAvatar from './images/avataaars.png';

function App() {

  return (
    <>
    <Navbar />
      <div className='homepage-container-web'>
        <Homepage />
        <About />
        <Skills />
      </div>
    <div className='homepage-container-devices'>
      <Routes>
        <Route path='/' element={<Homepage />} />
        <Route path='/about' element={<About />}/>
      </Routes>
    </div>
    </>
  );
}

export default App;

About.jsx:

import '../App.css';

function About() {
    return(
        <>
        <div className='about-container' id='about'>
            <h2 class='about-title'>A little bit about me...</h2>
            <p>Hi, my name is Andrew! I'm 20 years old, and I have <a href='https://www.crohnscolitisfoundation.org/what-is-crohns-disease' target="_blank" style={{color: '#a61bee'}}>Crohn's Disease</a>. Ever since I was 12 years old I have had an interest in technology, software engineering, cybersecurity, firefighting, and cars. I currently work for the Department of Defense and hold a Senior IT Specialist position. I am always looking to learn and improve myself.</p>
        </div>
        <div className='about-ending-container' />
        </>
    )
}

export default About;

1 Answer 1

2

The issue is that the first time it renders, when you do this

const aboutPage = document.getElementById('about');
const home = document.getElementById('home');
const skills = document.getElementById('skills');

those elements don't exist yet. The simplest solution would be to just change it to

const aboutPage = () => document.getElementById('about');
const home = () => document.getElementById('home');
const skills = () => document.getElementById('skills');

// ...

<li onClick={() =>{home().scrollIntoView({behavior: 'smooth'})}}>Home</li>
<li onClick={() =>{aboutPage().scrollIntoView({behavior: 'smooth'})}}>About</li>
<li onClick={() => {skills().scrollIntoView({behavior: 'smooth'})}}>Skills</li>

so that it does the search at the time of the click. That's not a very "react" way of doing it. But it should "just work".

If you want to do it the "right way", I supposed you'd want to use useRef, and hoist that up to the App. Using just home as an example, and omiting non-relevant code, it would be something like:

function App() {
    const homeRef = useRef();
    // ...
    <Navbar homeRef={homeRef} />
    // ...
    <Homepage ref={homeRef} />
}

function Navbar({ homeRef }) {
    const scrollIntoView = (ref) => {
        if (ref.current) {
            ref.current.scrollIntoView({behavior: 'smooth'})
        }
    }
    
    <li onClick={() =>{scrollIntoView(homeRef)}}>Home</li>
} 

const Homepage = React.forwardRef((props, ref) => {
    return(
        <>
            <div className='home-container' id='hone' ref={ref} >
                //...
            </div>
        </>
    )
})
Sign up to request clarification or add additional context in comments.

8 Comments

What would be the "React" way if you don't mind?
see edit, you'd need to use useRef, get a reference to the element by passing the ref down to the element,, pass the same ref to the other component so that it can use it.
I added your above code, however now I get the error "Uncaught TypeError: Cannot read properties of undefined (reading 'current') at scrollIntoView"
ah sorry, you'll need to use React.forwardRef reactjs.org/docs/forwarding-refs.html
I took a look at the documents and I am a bit confused on where I add the createRef and forwardRef?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.