简体   繁体   中英

How do I (correctly) check whether an element is within the viewport in React?

In a functional react component, I'm trying to check whether a call to action button (a different component) is within the viewport. If it's not, I want to display a fixed call to action button at the bottom of the viewport, which shows/hides, depending on whether the other button is visible.

I can do this using a combination of Javascript and react hooks, but although the code works in some components in my app, it doesn't work in others; I'm guessing due to react lifecycles.

I'm also aware that this is NOT the way I should be doing things in react, so would prefer to achieve the same result, but in a proper 'react way'.

I've been looking at using refs, but ideally wanted to avoid having to change my functional component to a class, as I'd like to use react hooks for the show/hide of the fixed cta. However, if this is a requirement in order to get the functionality I want, I could go for that.

Here's what I've got so far - basically, I want to replace document.querySelector with a react method:

  useEffect(() => {
    const CTA = document.querySelector('#CTANextSteps');
    const ApplyStyle = () => (isInViewport(CTA) ? setVisible(false) : setVisible(true));
    ApplyStyle();
    window.addEventListener('scroll', ApplyStyle);
    window.addEventListener('resize', ApplyStyle);
    return function cleanup() {
      window.removeEventListener('scroll', ApplyStyle);
      window.removeEventListener('resize', ApplyStyle);
    };
  });

  const isInViewport = (elem) => {
    const bounding = elem.getBoundingClientRect();
    return (
      bounding.top >= 0 &&
      bounding.left >= 0 &&
      bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  };

As mentioned above, this function works in some areas of the app without issue, but doesn't in others; I get a Cannot read property 'getBoundingClientRect' of null error. I was surprised it worked at all, but rather than tinkering with it to try and get it working everywhere, I want to rewrite it properly.

As always, any assistance would be much appreciated. Thanks.

I was able to do it with the depedency react-visibility-sensor@5.1.1

I followed the tutorial in this link and it worked fine with me.

I don't know if this is the correct way to do it, but it works!

Here is the link https://www.digitalocean.com/community/tutorials/react-components-viewport-react-visibility-sensor

I'll put an example just in case the previous link ever goes out.

import React, { Component } from 'react';
import VisibilitySensor from 'react-visibility-sensor';

class VisibilitySensorImage extends Component {
  state = {
    visibility: false
  }

  render() {
    return (
      <VisibilitySensor
        onChange={(isVisible) => {
          this.setState({visibility: isVisible})
        }}
      >
        <img
          alt={this.props.alt}
          src={this.props.src}
          style={{
            display: 'block',
            maxWidth: '100%',
            width: '100%',
            height: 'auto',
            opacity: this.state.visibility ? 1 : 0.25,
            transition: 'opacity 500ms linear'
          }}
        />
      </VisibilitySensor>
    );
  }
}

export default VisibilitySensorImage;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM