【问题标题】:ReactJS how to render a component only when scroll down and reach it on the page?ReactJS如何仅在向下滚动并在页面上到达组件时才呈现组件?
【发布时间】:2019-05-14 09:31:16
【问题描述】:

我有一个反应组件Data,其中包括几个图表组件; BarChartLineChart ...等

Data 组件开始渲染时,需要一段时间才能从 API 接收到每个图表所需的数据,然后它开始响应并渲染所有图表组件。

我需要的是,在我向下滚动并到达页面时才开始渲染每个图表。

有什么方法可以帮助我实现这一目标吗?

【问题讨论】:

标签: javascript reactjs react-chartjs


【解决方案1】:

您至少有三个选项可以做到这一点:

  1. 跟踪组件是否在视口中(对用户可见)。然后渲染它。你可以使用这个 HOC https://github.com/roderickhsiao/react-in-viewport

  2. 使用https://react-fns.netlify.com/docs/en/api.html#scroll明确跟踪“y”滚动位置

  3. 使用 Intersection Observer API https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API编写您自己的 HOC

要渲染组件,您可能需要另一个 HOC,它将根据收到的道具返回 Chart 组件或“null”。

【讨论】:

  • 我用 react-visibility-sensor 代替 react-in-viewport,如下:onChange = (isVisible)=>{ this.setState({isChart1Visible: isVisible}); } render(){ <VisibilitySensor onChange={this.onChange}> {this.state.isChart1Visible? <BarChart getData={this.getData} /> : null} </VisibilitySensor> }。但是一旦图表在视口中,我仍然坚持如何渲染图表! VisibilitySensor 组件仅接受显式子元素,不接受条件短语。我该如何解决?
  • @Shatha 您需要使用 react-visibility-sensor 包装所有图表。这是一个例子pastebin.com/hZJF0C82
【解决方案2】:

我尝试了很多库,但找不到最适合我需要的东西,所以我为此编写了一个自定义钩子,希望对您有所帮助

import { useState, useEffect } from "react";

const OPTIONS = {
  root: null,
  rootMargin: "0px 0px 0px 0px",
  threshold: 0,
};

const useIsVisible = (elementRef) => {
  const [isVisible, setIsVisible] = useState(false);

  useEffect(() => {
    if (elementRef.current) {
      const observer = new IntersectionObserver((entries, observer) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            setIsVisible(true);
            observer.unobserve(elementRef.current);
          }
        });
      }, OPTIONS);
      observer.observe(elementRef.current);
    }
  }, [elementRef]);

  return isVisible;
};

export default useIsVisible;

然后你可以按如下方式使用钩子:

import React, { useRef } from "react";
import useVisible from "../../hooks/useIsVisible";

function Deals() {
  const elemRef = useRef();
  const isVisible = useVisible(elemRef);
  return (
    <div ref={elemRef}>hello {isVisible && console.log("visible")}</div>
)}

【讨论】:

    【解决方案3】:

    您可以检查窗口滚动位置以及滚动位置是否在您的 div 附近 - 显示它。 为此,您可以使用简单的反应渲染条件。

    import React, {Component} from 'react';
    import PropTypes from 'prop-types';
    
    class MyComponent extends Component {
    constructor(props){
        super(props);
    
        this.state = {
            elementToScroll1: false,
            elementToScroll2: false,
        }
    
        this.firstElement = React.createRef();
        this.secondElement = React.createRef();
    }
    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll);
    }
    
    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll);
    }
    handleScroll(e){
        //check if scroll position is near to your elements and set state {elementToScroll1: true}
        //check if scroll position is under to your elements and set state {elementToScroll1: false}
    }
    render() {
        return (
            <div>
                <div ref={this.firstElement} className={`elementToScroll1`}>
                    {this.state.elementToScroll1 && <div>First element</div>}
                </div>
                <div ref={this.secondElement} className={`elementToScroll2`}>
                    {this.state.elementToScroll2 && <div>Second element</div>}
                </div>
            </div>
        );
    }
    }
    
    MyComponent.propTypes = {};
    
    export default MyComponent;
    

    这可能会对您有所帮助,这只是一个快速的解决方案。它会为您生成一些重新渲染操作,因此请注意。

    【讨论】:

    • 感谢您的回答。实际上我希望它是动态的,而不是检查每个图形的位置然后渲染它。因为我可能有很多图表,并且在代码更新期间它们的位置可能每次都不同。这就是我在comment 中提到的使用 react-visibility-sensor 的原因,它检查元素是否在视口中。但是,一旦图表在视口中,我仍然无法实现渲染图表
    【解决方案4】:

    我认为在 React 中最简单的方法是使用 react-intersection-observer

    例子:

    import { useInView } from 'react-intersection-observer';
    
    const Component = () => {
      const { ref, inView, entry } = useInView({
        /* Optional options */
        threshold: 0,
      });
    
      useEffect(()=>{
          //do something here when inView is true
      }, [inView])
    
      return (
        <div ref={ref}>
          <h2>{`Header inside viewport ${inView}.`}</h2>
         </div>
      );
    };
    

    我还建议在选项对象中使用triggerOnce: true,这样效果只会在用户第一次滚动到它时发生。

    【讨论】:

      猜你喜欢
      • 2021-12-22
      • 1970-01-01
      • 2020-11-12
      • 2021-01-20
      • 1970-01-01
      • 2019-08-21
      • 1970-01-01
      • 2021-04-18
      • 2018-01-17
      相关资源
      最近更新 更多