HNWeb
HNWeb

Reputation: 29

How to fix "TypeError: this.getElement(...) is null"

I'm creating an array which will include the heights of some components in my app.

for doing that I had to get the elements and their heights.
I did it by this function:

getElement(method, elem){
    switch (method){
      case 'id':
        return document.getElementById(elem);
      case 'class':
        return document.getElementsByClassName(elem);
      case 'name':
        return document.getElementsByName(elem);
      case 'tagName':
        return document.getElementsByTagName(elem);
      default:
        console.error('Incorrect use of getElement method')
    }
  }

and then I was inserting the heights of the elements by this function to my array:

  heightsArr = [
    this.getElement('id', 'home').clientHeight,
    this.getElement('id', 'services').clientHeight
  ]

but then I'm getting an error:

TypeError: this.getElement(...) is null

I was trying to move the array to componentDidMount() function, and then the error disappeared.
but then when I called the array, it returned me undefined

When it was in the componentDidMount() I was trying to do console.log() to the array, and it returns the array as expected with all of the heights

I'm trying to set set this array as NavBar component by this code:

<NavBar heights={this.heightsArr}></NavBar>

but when I was inspecting the component by react addon for firefox, I saw that the props of the component are

{
   heights: undefined
}

how can I fix it?

EDIT:

Now it's working and with the react inpector on the browser, I see that the heights are finnaly props of NavBar.

I'm setting the props as property of an object in an array, but when I'm logging to the console the value of that property I'm getting undefined.

My code that assigning the props to the object is:

componentDidMount() {
    this.sections.map(section => {
      section.height = this.props.heights
    })
}

Should I move this map function to componentDidUpdate() instead of componentDidMount()?

Upvotes: 1

Views: 662

Answers (2)

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

React has access to the virtual DOM rather than the one you typically interact with using traditional dom selectors. To coordinate with React's lifecycle events, you should use React refs instead.

Consider this sandbox: https://codesandbox.io/s/angry-wood-bp95g

Working code:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      totalHeight: 0
    };

    this.home = React.createRef();
    this.services = React.createRef();
  }

  componentDidMount() {
    let allHeights = 0;
    const refs = [this.home, this.services];

    refs.forEach(ref => {
      allHeights += ref.current.clientHeight;
    });

    this.setState({
      totalHeight: allHeights
    });
  }

  render() {
    return (
      <div>
        <h4>Height: {this.state.totalHeight}</h4>
        <div ref={this.home} style={{ height: "500px", background: "blue" }}>
          Home Section
        </div>
        <div
          ref={this.services}
          style={{ height: "300px", background: "green" }}
        >
          Services
        </div>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Refs give you access to the same element properties and methods you would with traditional selectors. In this case, we give each <div> tag a ref. Inside componentDidMount(), which is triggered right after the first render, we can tap into the height of these mounted elements using their .clientHeight as expected.

We iterate over the refs to get the total height and update our totalHeight state-value. Similarly you can pass in that state to your Navbar component like:

<Navbar height={this.state.heights}/>

Upvotes: 2

Jackkobec
Jackkobec

Reputation: 6705

Also you can control element for not null or undefined on insert to array:

heightsArr = [
    this.getElement('id', 'home') && this.getElement('id', 'home').clientHeight,
    this.getElement('id', 'services') && this.getElement('id', 'services').clientHeight
  ]

Upvotes: 2

Related Questions