旧观察目标上的Intersection Observer API触发回调

时间:2019-06-30 09:58:03

标签: javascript reactjs intersection-observer

背景

我正在开发一个基于React的简单歌词应用程序。

目标

当用户向下滚动艺术家列表时,使用Intersection Observer API加载更多艺术家。

信息

驱动前端的API具有分页功能。 offset0开始,而limit10。对API的调用如下:

https://api.bejebeje.com/artists?offset=0&limit=10

整个应用程序是deployed here。我在代码中包含有用的console.log()语句,因此打开Chrome开发工具会有所帮助。

代码

所有代码均为开放源代码,并且为sits on GitHub。我正在处理的分支是 feature / intersection-api-enhancements

这里是App.jsx组件:

import React, { useRef, useCallback, useState, useEffect } from "react";
import { render } from "react-dom";
import { Router } from "@reach/router";
import axios from "axios";
import Authorisation from "./components/Authorisation/Authorisation";
import Artists from "./components/Artists/Artists";
import ArtistLyrics from "./components/ArtistLyrics/ArtistLyrics";
import Lyric from "./components/Lyric/Lyric";
import { API_CONSTANTS } from "./helpers/apiEndpoints";
import "./App.css";

function App() {
  const [artists, setArtists] = useState([]);
  const offset = useRef(0);
  const limit = 10;

  const callback = entries => {
    console.log(
      `Intersection callback fired. isIntersecting is ${
        entries[0].isIntersecting
      }.`
    );
    if (entries[0].isIntersecting) {
      console.log("about to fetch artists ...");
      fetchArtists(offset, limit);
    }
  };

  const fetchArtists = (offset, limit) => {
    axios.get(API_CONSTANTS.artists(offset.current, limit)).then(result => {
      const artistsArray = result.data.artists;
      setArtists([...artists, ...artistsArray]);
      offset.current += artistsArray.length;
      console.log(`offset is now at ${offset.current}.`);
    });
  };

  useEffect(() => {
    fetchArtists(offset, limit);
  }, []);

  return (
    <div>
      <Router>
        <Artists path="/" artists={artists} intersectionCallback={callback} />
        <ArtistLyrics path="artists/:artistSlug/lyrics" />
        <Lyric path="artists/:artistSlug/lyrics/:lyricSlug" />
        <Authorisation path="/callback" />
      </Router>
    </div>
  );
}

render(<App />, document.getElementById("root"));

这是Artists.jsx组件:

import React, { useEffect, useRef } from "react";
import Header from "../Header/Header";
import "./Artists.css";
import ArtistCard from "../ArtistCard/ArtistCard";

function Artists(props) {
  const getPrimaryArtistSlug = slugs => {
    return slugs.filter(slug => slug.isPrimary)[0].name;
  };

  const singleRefs = props.artists.reduce((acc, value, index) => {
    acc[index] = React.createRef();
    return acc;
  }, {});

  const observer = new IntersectionObserver(props.intersectionCallback, {
    root: null,
    threshold: 0.8
  });

  useEffect(() => {
    if (props.artists.length > 0) {
      const indexOfLastArtist = props.artists.length - 2;
      observer.observe(singleRefs[indexOfLastArtist].current);
      const entries = observer.takeRecords();
    }
  }, [props.artists]);

  return (
    <>
      <Header title="Browse" />
      <div className="artists__list">
        {props.artists.map((artist, index) => {
          const primarySlug = getPrimaryArtistSlug(artist.slugs);
          return (
            <ArtistCard
              key={primarySlug}
              artist={artist}
              primarySlug={primarySlug}
              itemRef={singleRefs[index]}
            />
          );
        })}
      </div>
    </>
  );
}

export default Artists;

问题

每次重新渲染Artists.jsx时,都会得到一个新的IntersectionObserver,然后将观察目标设置为artists数组中位于last之前的项目。因此,当props.artists有10个项目时,目标是列表中的第9位艺术家。当props.artists有20个项目时,目标是列表中的第19个艺术家,依此类推。

在初始页面加载时,所有功能似乎都能按预期工作,我向下滚动到第9个项目,并对该API进行了新调用,并加载并渲染了10个以上的艺术家。

新目标应该是第19位艺术家。但是,如果我向上滚动然后向下滚动经过第9个艺术家,则回调会再次触发!这是为什么?第9个演出者项目不再是观察者的目标,因此我不确定为什么它出现时会触发回调。我很困惑。

0 个答案:

没有答案