ReactJS 如何仅在向下滚动并到达页面时才呈现组件?
ReactJS how to render a component only when scroll down and reach it on the page?
我有一个 React 组件 Data
,其中包含几个图表组件; BarChart
LineChart
...等等
当Data
组件开始渲染时,需要一段时间才能从API接收到每个图表所需的数据,然后开始响应并渲染所有图表组件。
我需要的是,当我向下滚动并到达页面上时仅开始渲染每个图表。
有什么办法可以帮助我实现这个目标吗??
您至少有三种选择:
跟踪组件是否在视口中(对用户可见)。然后渲染它。你可以使用这个 HOC https://github.com/roderickhsiao/react-in-viewport
明确跟踪“y”滚动位置
使用 Intersection Observer 编写您自己的 HOC API https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
要渲染组件,您可能需要另一个 HOC,它将 return 图表组件或根据它接收到的道具为“空”。
您可以检查 window 滚动位置,如果滚动位置靠近您的 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;
这可能对您有所帮助,这只是一个快速解决方案。它会生成一些重新渲染操作,所以请注意。
我尝试了很多库,但找不到最适合我需要的库,所以我为此编写了一个自定义挂钩,希望它能有所帮助
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>
)}
我认为在 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
,这样效果只会在用户第一次滚动到它时发生。
我有一个 React 组件 Data
,其中包含几个图表组件; BarChart
LineChart
...等等
当Data
组件开始渲染时,需要一段时间才能从API接收到每个图表所需的数据,然后开始响应并渲染所有图表组件。
我需要的是,当我向下滚动并到达页面上时仅开始渲染每个图表。
有什么办法可以帮助我实现这个目标吗??
您至少有三种选择:
跟踪组件是否在视口中(对用户可见)。然后渲染它。你可以使用这个 HOC https://github.com/roderickhsiao/react-in-viewport
- 明确跟踪“y”滚动位置
使用 Intersection Observer 编写您自己的 HOC API https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
要渲染组件,您可能需要另一个 HOC,它将 return 图表组件或根据它接收到的道具为“空”。
您可以检查 window 滚动位置,如果滚动位置靠近您的 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;
这可能对您有所帮助,这只是一个快速解决方案。它会生成一些重新渲染操作,所以请注意。
我尝试了很多库,但找不到最适合我需要的库,所以我为此编写了一个自定义挂钩,希望它能有所帮助
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>
)}
我认为在 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
,这样效果只会在用户第一次滚动到它时发生。