Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

90 lines of code, 15 elements to achieve infinite scrolling

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/02 Report--

Preface

In this article you will learn:

The use of IntersectionObserver API and how to be compatible.

How to implement infinite scrolling in React Hook.

How to correctly render a list of up to 10000 elements.

Unlimited drop-down loading technology allows users to scroll in front of large chunks of content. This method is to keep loading new content as you scroll down.

When you use scrolling as the main method of discovering data, it may make your users stay on the page longer and increase user engagement. With the popularity of social media, a large amount of data is consumed by users. Wireless scrolling provides an efficient way for users to browse huge amounts of information without having to wait for the page to preload.

How to build an infinite scrolling with a good experience is a topic that every front-end will encounter whether it is a project or an interview.

The original implementation of this article comes from: Creating Infinite Scroll with 15 Elements

1. Early solution

With regard to infinite scrolling, early solutions basically relied on listening for scroll events:

Function fetchData () {fetch (path) .then (res = > doSomeThing (res.data));} window.addEventListener ('scroll', fetchData); copy code

Then calculate various .scrollTop (), .offset () .top, and so on.

Writing one by hand is also very boring. And:

Scroll events are triggered frequently, so we also need manual throttling.

There is a large amount of DOM in the scrolling element, which is easy to cause stutter.

Then came the cross-observer IntersectionObserver API, and after the framework for data-driven views such as Vue and React, a general solution for infinite scrolling came out. two。 Cross-observer: IntersectionObserver

Const box = document.querySelector ('.box'); const intersectionObserver = new IntersectionObserver ((entries) = > {entries.forEach ((item) = > {if (item.isIntersecting) {console.log ('enter the visual area');}})); intersectionObserver.observe (box); copy code

Hit the point: IntersectionObserver API is asynchronous and does not trigger synchronously with the scrolling of the target element, resulting in extremely low performance consumption.

2.1 IntersectionObserverEntry object

Here I would like to give a rough introduction to what you need: the first try of IntersectionObserve

IntersectionObserverEntry object

When the callback function is called, it is passed an array in which each object is the object currently entering or leaving the visual area (IntersectionObserverEntry object)

This object has many properties, the most commonly used of which are:

Target: the observed target element, which is a DOM node object

IsIntersecting: whether to enter the visual area

IntersectionRatio: the scale value of the intersection area and the target element, which enters the visual area. The value is greater than 0, otherwise it equals 0.

2.3 options

When calling IntersectionObserver, in addition to passing a callback function, you can also pass in an option object and configure the following attributes:

Threshold: determines when to trigger the callback function. It is an array with a threshold for each member, which defaults to [0], that is, the callback function is triggered when the intersectionRatio reaches 0. Users can customize this array. For example, [0, 0.25, 0.5, 0.75, 1] means that the callback function will be triggered when the target elements 0%, 25%, 50%, 75%, and 100% are visible.

Root: the root element for observation. The default is the browser's viewport. You can also specify a specific element. When you specify an element, the element used for observation must be a child of the specified element.

RootMargin: used to enlarge or reduce the size of windows, using the definition method of css, 10px 10px 30px 20px represents the values of top, right, bottom, and left

Const io = new IntersectionObserver ((entries) = > {console.log (entries);}, {threshold: [0,0.5], root: document.querySelector ('.container'), rootMargin: "10px 10px 30px 20px",}); copy code

2.4 observer

Observer.observer (nodeone); / / only observe nodeOne observer.observer (nodeTwo); / / observe nodeOne and nodeTwo observer.unobserve (nodeOne); / / stop watching nodeOneobserver.disconnect (); / / do not observe any node copy code

3. How to use IntersectionObserver in React Hook

Before looking at the Hooks version, let's take a look at the normal component version:

Class SlidingWindowScroll extends React.Component {this.$bottomElement = React.createRef ();... componentDidMount () {this.intiateScrollObserver ();} intiateScrollObserver = () = > {const options = {root: null, rootMargin: '0pxcodes, threshold: 0.1}; this.observer = new IntersectionObserver (this.callback, options); this.observer.observe (this.$bottomElement.current);} render () {return ()} copy code

As we all know, React 16.x introduced useRef to replace the original createRef, which is used to track DOM nodes. Then let's get started:

4. Principle

Implement a component that displays a list of n items with a fixed window size of 15 elements: that is, there are only 15 DOM nodes on the infinite scroll n element at any time.

Use relative/absolute positioning to determine the rolling position

Track two ref: top/bottom to determine whether to scroll up / down to render or not

Cut the list of data, retaining up to 15 DOM elements.

5. UseState declares state variables

Let's start writing the component SlidingWindowScrollHook:

Const THRESHOLD = 1510 Const SlidingWindowScrollHook = (props) = > {const [start, setStart] = useState (0); const [end, setEnd] = useState (THRESHOLD); const [observer, setObserver] = useState (null); / / other code.} copy code

1. Simple understanding of useState:

Const [property, method of manipulating property] = useState (default); copy code

two。 Variable analysis

Start: the first data in the currently rendered list. Default is 0.

End: the last data in the currently rendered list. Default is 15.

Observer: the currently observed view ref element

6. UseRef defines the DOM element of the trace

Const $bottomElement = useRef (); const $topElement = useRef (); copy code

Normal infinite scrolling down only needs to focus on one dom element, but since we are rendering with 15 fixed dom elements, we need to determine whether to scroll up or down.

7. Internal operation method and corresponding useEffect

Please eat with the notes:

UseEffect (() = > {/ / define observation intiateScrollObserver (); return () = > {/ / abandon observation resetObservation ()}}, [end]) / / because [end] is a synchronous refresh, just use one here. / / define observation const intiateScrollObserver = () = > {const options = {root: null, rootMargin: '0pxstories, threshold: 0.1}; const Observer = new IntersectionObserver (callback, options) / / observe the beginning and end elements if ($topElement.current) {Observer.observe ($topElement.current);} if ($bottomElement.current) {Observer.observe ($bottomElement.current) } / / set the initial value setObserver (Observer)} / / the specific callback of cross observation, observe each node, and process the real-time header and tail element index const callback = (entries, observer) = > {entries.forEach ((entry, index) = > {const listLength = props.list.length; / / scroll down, refresh the data if (entry.isIntersecting & & entry.target.id = = "bottom") {const maxStartIndex = listLength-1-THRESHOLD / / current header index const maxEndIndex = listLength-1; / / current tail index const newEnd = (end + 10) 0? Start-10: 0); / / the minimum value of the header element index is 0 setStart (newStart) setEnd (newEnd)}});} / / abandon viewing when scrolling is stopped const resetObservation = () = > {observer & & observer.unobserve ($bottomElement.current); observer & & observer.unobserve ($topElement.current);} / / when rendering, the header and tail ref process const getReference = (index, isLastIndex) = > {if (index = 0) return $topElement; if (isLastIndex) return $bottomElement; return null;} copy code

8. Rendering interface

Const {list, height} = props; / / data, node height const updatedList = list.slice (start, end); / / data cutting const lastIndex = updatedList.length-1; return ({updatedList.map ((item, index) = > {const top = (index + start)) + 'px'; / / const refVal = getReference (index, index = lastIndex) based on relative & absolute positioning; / / head-tail ref const id = index = 0? 'top': (index = lastIndex? 'bottom':'); / / bind ID return ({item.value});}); copy code

9. How to use

App.js:

Import React from 'react';import'. / App.css';import {SlidingWindowScrollHook} from ". / SlidingWindowScrollHook"; import MY_ENDLESS_LIST from'. / Constants';function App () {return (15 elements achieve infinite scrolling);} export default App; copy code

Define the data Constants.js:

Const MY_ENDLESS_LIST = [{key: 1, value:'A'}, {key: 2, value:'B'}, {key: 3, value:'C'}, / / Don't paste it in the middle. {key: 45, value: 'AS'}] copy the code

SlidingWindowScrollHook.js:

Import React, {useState, useEffect, useRef} from "react"; const THRESHOLD = 15 const Const SlidingWindowScrollHook = (props) = > {const [start, setStart] = useState (0); const [end, setEnd] = useState (THRESHOLD); const [observer, setObserver] = useState (null); const $bottomElement = useRef (); const $topElement = useRef (); useEffect () = > {intiateScrollObserver () Return () = > {resetObservation ()} / / eslint-disable-next-line react-hooks/exhaustive-deps}, [start, end]) const intiateScrollObserver = () = > {const options = {root: null, rootMargin: '0pxrabbit, threshold: 0.1}; const Observer = new IntersectionObserver (callback, options) if ($topElement.current) {Observer.observe ($topElement.current);} if ($bottomElement.current) {Observer.observe ($bottomElement.current) } setObserver (Observer)} const callback = (entries, observer) = > {entries.forEach ((entry, index) = > {const listLength = props.list.length; / / Scroll Down if (entry.isIntersecting & & entry.target.id = "bottom") {const maxStartIndex = listLength-1-THRESHOLD; / / Maximum index value `start` can take const maxEndIndex = listLength-1; / / Maximum index value `end` can take const newEnd = (end + 10) 0? Start-10: 0); setStart (newStart) setEnd (newEnd)}});} const resetObservation = () = > {observer & & observer.unobserve ($bottomElement.current); observer & & observer.unobserve ($topElement.current);} const getReference = (index, isLastIndex) = > {if (index = 0) return $topElement; if (isLastIndex) return $bottomElement; return null;} const {list, height} = props; const updatedList = list.slice (start, end); const lastIndex = updatedList.length-1 Return ({updatedList.map ((item, index) = > {const top = (height * (index + start)) + 'px'; const refVal = getReference (index, index = lastIndex); const id = index = 0? 'top': (index = lastIndex? 'bottom':'); return ({item.value});})});} export {SlidingWindowScrollHook}; copy the code

And a few styles:

.li-card {display: flex; justify-content: center; list-style: none; box-shadow: 2px 2px 9px 0px # bbb; padding: 70px 0; margin-bottom: 20px; border-radius: 10px; position: absolute; width: 80%;} copy the code

Then you can play slowly.

10. Compatibility processing

IntersectionObserver is not compatible with Safari?

Don't panic, we have the polyfill version.

340000 downloads a week, don't worry about it, brothers.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report