我有一个Data
包含几个图表组件的react组件;BarChart
LineChart
...等等。
当Data
组件开始渲染时,需要一段时间才能从 API 接收到每个图表所需的数据,然后它开始响应并渲染所有图表组件。
我需要的是,仅当我向下滚动并到达页面时才开始渲染每个图表。
有什么办法可以帮助我实现这一目标?
我有一个Data
包含几个图表组件的react组件;BarChart
LineChart
...等等。
当Data
组件开始渲染时,需要一段时间才能从 API 接收到每个图表所需的数据,然后它开始响应并渲染所有图表组件。
我需要的是,仅当我向下滚动并到达页面时才开始渲染每个图表。
有什么办法可以帮助我实现这一目标?
您至少有三个选项可以做到这一点:
跟踪组件是否在视口中(对用户可见)。然后渲染它。你可以使用这个 HOC https://github.com/roderickhsiao/react-in-viewport
使用https://react-fns.netlify.com/docs/en/api.html#scroll明确跟踪“y”滚动位置
使用 Intersection Observer API https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API编写您自己的 HOC
要渲染组件,您可能需要另一个 HOC,它会根据它收到的 props 返回 Chart 组件或“null”。
我尝试了很多库,但找不到最适合我需要的东西,所以我为此编写了一个自定义钩子,希望对您有所帮助
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>
)}
您可以检查窗口滚动位置,如果滚动位置靠近您的 div - 显示它。为此,您可以使用简单的react渲染条件。
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;
这可能对您有所帮助,这只是一个快速的解决方案。它会为您生成一些重新渲染操作,因此请注意。
我认为在 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
在选项对象中使用,这样效果只会在用户第一次滚动到它时发生。