Фон
Я работаю над простым приложением песни, встроенным в React.
Цель
Использование Intersection ObserverAPI для загрузки большего количества исполнителей, когда пользователь прокручивает список исполнителей вниз.
Информация
API, управляющий внешним интерфейсом, имеет подкачку страниц.offset
начинается с 0
, а limit
- 10
.Вызов API выглядит следующим образом:
https://api.bejebeje.com/artists?offset=0&limit=10
Все приложение развернуто здесь .У меня есть полезные операторы console.log()
в коде, поэтому поможет открытие Chrome Dev Tools.
Код
Весь код с открытым исходным кодом и сидит наGitHub .Ветвь, над которой я работаю: feature / intersection-api-extensions .
Вот компонент 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
и затем устанавливаю наблюдениецелевой элемент до последнего в массиве художников.Поэтому, когда у props.artists
есть 10 элементов, цель - 9-й художник в списке.Когда props.artists
имеет 20 элементов, целью является 19-й исполнитель в списке и т. Д.
При начальной загрузке страницы все работает, как и ожидалось, я прокручиваю вниз до 9-го элемента и получаю новыйвыполняется вызов API, и загружаются и обрабатываются еще 10 художников.
Новая цель должна быть 19-м художником.И все же, если я прокручиваю вверх, затем прокручиваю вниз мимо 9-го художника, обратный вызов снова срабатывает!Это почему?Девятый элемент артиста больше не является целью наблюдателя, поэтому я не уверен, почему он вызывает обратный вызов, когда он появляется.Я в замешательстве.