Search code examples
javascriptreactjsobservers

Use intersection observer in react


I need to change elementA when elementB is out from viewport. I have html elements

<header id="header">
<div id="banner">

and js:

const banner = document.getElementById('banner');
const nav = document.getElementById('navbar');
const callback = ([entry]) => {
  const { isIntersecting } = entry;
  nav.classList.toggle('navOpacity', !isIntersecting);
};
const options = {
  root: null,
  rootMargin: '0px',
  threshold: 0.0
};
const observer = new IntersectionObserver(callback, options);
observer.observe(banner);

It works. Next i tried to use it in react component:

export default class Home extends Component {
  constructor() {
    super();
    this.state = {
      isInView: null,
      BannerRef: React.createRef()
    };
  }

  componentDidMount() {
    const callback = ([entry]) => {
      const { isIntersecting } = entry;
      this.setState({ isInView: !isIntersecting });
    };

    const options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.0
    };

    const observer = new IntersectionObserver(callback, options);

    observer.observe(
      this.BannerRef
    );
  }

  render() {
    const { isInView, BannerRef } = this.state;
    return (
      <>
        <Nav isInView={isInView} />
        <Banner RefProp={BannerRef} />
        <ContentNews />
        <ContentBelow />
        <Footer />
      </>
    );
  }
}

And in Banner component ref is in first <>

but Uncaught TypeError: Failed to execute 'observe' on 'IntersectionObserver': parameter 1 is not of type 'Element'.

Please helm me understand how does it work.

UPD:

-BannerRef: React.createRef()
+this.BannerRef.current
-this.BannerRef
+this.BannerRef = React.createRef();

export default class Home extends Component {
  constructor() {
    super();
    this.state = {
      isInView: false,
    };
    this.BannerRef = React.createRef();
  }

  componentDidMount() {
    const callback = ([entry]) => {
      const { isIntersecting } = entry;
      this.setState({ isInView: !isIntersecting });
    };

    const options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.0
    };

    const observer = new IntersectionObserver(callback, options);

    observer.observe(
      this.BannerRef.current
    );
  }

  render() {
    const { isInView } = this.state;
    return (
      <>
        <Nav isInView={isInView} />
        <Banner RefProp={this.BannerRef} />
        <ContentNews />
        <ContentBelow />
        <Footer />
      </>
    );
  }
}

Solution

  • Try to

    observer.observe(
      this.BannerRef.current 
    );
    

    Also read the docs here