React:方法在componentDidMount上返回错误的值

问题描述 投票:0回答:3

我想只在视口中的组件中做一些事情。它几乎可以工作,但我有一个我无法管理的问题。

class Hello extends React.Component {

  componentDidMount() {
    console.log(this.isInViewPort()) // false for second element - last in viewport
    if (this.isInViewPort()) {
    console.log("I'm in viewport!");
    }
    window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }

  isInViewPort = () => {
    const element = this.refs[this.props.id];
    const rect = element.getBoundingClientRect();
    const windowHeight = window.innerHeight || document.documentElement.clientHeight;
    const result = rect.top <= windowHeight && rect.top + rect.height >= 0;
    return result;
  }

  handleScroll = () => {
    if (this.isInViewPort()) {
        console.log("I'm in viewport!");
    }
  }

  render() {
    return (
        <div className="example" ref={this.props.id} onClick={this.handleScroll} /> // onClick added for tests
    );
  }
}


class App extends React.Component {
  render() {
    return (
      <Hello id={1} />
      <Hello id={2} />
      <Hello id={3} />
    );
  }
}


.example {
  width: 400px;
  height: 400px;
  background-color: red;
}

当我加载页面时,两个元素在视口中。第一个 - 视口中的100%和第二个 - 在视口中可能是15-20%。

对于此示例,我只有一个console.log,因此this.isInViewPort()仅对第一个元素为true。这是错误的,因为其中两个是可见的。

当我触摸事件滚动时,组件立即可见方法并生成控制台日志。当我不触摸滚动,但点击第二个组件(这是为测试添加)方法返回true,我得到console.log。

我希望通过方法返回每个可见元素时的情况。

它在我这样做时有效:

componentDidMount() {
    setTimeout(() => {
      if (this.isInViewPort()) {
        console.log("I'm in viewport!");
    }, 0);
}

但对于100%这不是一个好的解决方案。当我将此代码放在componentDidUpdate()的重构之后,它也不起作用。

这是反应生命周期的事情吗?我没有做任何巫婆状态,这就是为什么我不能理解。

javascript reactjs
3个回答
1
投票

我相信您的问题可能与您测试项目的位置以及如何提交文件等有关。我创建了一个小提琴来测试它:

.example {
  width: 400px;
  height: 90vh;
  background-color: red;
  border: 1px solid black;
}

https://jsfiddle.net/284Ldvkc/

我只将高度从400px改为90vh,所以我确保总是1在视野中,2在视野中有10%。


1
投票

工作正常

class Hello extends React.Component {
  componentDidMount() {
    this.isInViewPort()
    window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }

  isInViewPort = () => {
    const element = this.refs[this.props.id];
    const rect = element.getBoundingClientRect();
    const windowHeight = window.innerHeight || document.documentElement.clientHeight;
    const result = rect.top <= windowHeight && rect.top + rect.height >= 0;
    this.props.onLog(result ? `${this.props.id} in view port` : `${this.props.id} outside`)
    return result;
  }


  handleScroll = () => {
    this.isInViewPort()
  }

  render() {
    return (<div className="example" ref={this.props.id} onClick={this.handleScroll} />
    );
  }
}
class App extends React.Component {
  render() {
    return <div>
      <Hello id={1} onLog={console.info} />
      <Hello id={2} onLog={console.info} />
      <Hello id={3} onLog={console.info} />
     </div>;
  }
}

ReactDOM.render(<App /> ,
  document.getElementById('container')
);
.example {
  width: 400px;
  height: 400px;
  background-color: red;
}

.example:first-child {
  background-color: pink;
}

.example:last-child {
  background-color: blue;
}
.as-console-wrapper {
  height: 62px!important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container" />

1
投票

在StackOverflow中,您可以找到检查“DOM element is visible in the current viewport”的最佳方法。

我刚补充说:

isElementInViewport = el => {
    var rect = el.getBoundingClientRect();

    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <=
        (window.innerHeight ||
          document.documentElement.clientHeight) /*or $(window).height() */ &&
      rect.right <=
        (window.innerWidth ||
          document.documentElement.clientWidth) /*or $(window).width() */
    );
  };

并从以下地址拨打:

isInViewPort = () => {
    const element = this.refs[this.props.id];
    console.log("isInViewPort:" + this.props.id);
    return this.isElementInViewport(element);
  };

你可以在codesandbox.io上测试一下

© www.soinside.com 2019 - 2024. All rights reserved.