Nasza strona używa cookies. Dowiedz się więcej o celu ich używania i zmianie ustawień w przeglądarce. Korzystając ze strony, wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki. Rozumiem

Nieskończone przewijanie z React Hooks

Alec Kan Full Stack Web Developer / Thinkful
Sprawdź, jak dzięki React Hooks zaimplementować funkcję nieskończonej listy i poprawić jakości UX w Twojej aplikacji.
Nieskończone przewijanie z React Hooks

Funkcja nieskończonej listy (przewijania) istnieje już od jakiegoś czasu. Jest to świetny sposób na poprawę jakości UX w Twojej aplikacji.

Dostępnych jest wiele bibliotek, które powstały właśnie do takich celów, ale jeśli tak jak ja, chcesz rzucić sobie wyzwanie, to zbadaj ze mną implementację od zera, używając w tym celu Hooks.

Zbudujmy zatem na szybko prosty komponent aplikacji. Inicjalizujemy pusty stan i przekazujemy referencje do state i setState jako propy do naszego komponentu InfiniteList.

export default function App() {
  
  const [state, setState] = useState([]);
return (
    <div className='App'>
      <InfiniteList 
        state={state}
        setState={setState}
      />
    </div>
  );
};


Komponent InfiniteList zwróci nieuporządkowaną listę zdjęć piesków pobranych z Dog API.

Kiedy nasze żądanie się powiedzie, przekazujemy zdjęcia do stanu rodzica. Upewnijmy się, że nie nadpiszemy poprzedniego stanu, ponieważ będziemy używać funkcji getData() wielokrotnie, aby pobrać więcej obrazów. A zatem - kropka, kropka, kropka . . . 

function InfiniteList(props) {
useEffect(() => {
    getData();
  }, []);
const getData = () => {
    fetch('https://dog.ceo/api/breeds/image/random/15')
      .then(res => {
        return !res.ok 
        ? res.json().then(e => Promise.reject(e))
        : return res.json()
      }
      .then(res => props.setState([...props.state, ...res.message]))
      .catch(console.log);
}
return (
    <ul id='list'>
      { props.state.map((img, i) => (
          <li key={i} style={{backgroundImage: `url(${img})`}}/>)}
    </ul>
  );


Jak dotąd, wyświetla nam to pierwsze 15 obrazów.

Teraz musimy nasłuchiwać zdarzenia, gdy użytkownik przejdzie do samego dołu listy i pobierze więcej obrazów, przywołując getData() ponownie.

Ale jak określamy dolny zasięg? Mam nadzieję, że ten obrazek to wyjaśni.



  1. window.innerHeight - statyczne, wysokość okna przeglądarki użytkownika.
  2. window.scrollY - właściwość dynamiczna, aktualna pozycja przewijania.
  3. list.clientHeight - statyczne, wysokość kontenera (element ul).
  4. list.offsetTop - wcięcie kontenera (jeśli występuje) od góry strony, statyczne.



Zatem, jeśli 1+2===3+4, wiemy, że użytkownik znajduje się na dole strony i musimy rozpocząć pobieranie.

Ale co, jeśli chcemy, żeby ul miało stałą wysokość? Musimy pobrać właściwości ul:

  1. element.scrollHeight - wartość statyczna, całkowita przewijalna wysokość.
  2. element.scrollTop - wartość dynamiczna, aktualna pozycja górnego przewijania.
  3. element.clientHeight - wartość statyczna, aktualna wysokość elementu (bez overflow).



W związku z tym, 1===2+3 oznacza, że użytkownik dosięgnął dna kontenera. Teraz możemy warunkowo stwierdzić, czy jest to element o stałej wysokości, ustawiając właściwość scrollable.

Zbierzmy to wszystko w nowy hook useEffect.

Jest jeszcze jedna, ostatnia poprawka do wprowadzenia, żeby to wszystko zadziałało. Zainicjujemy stan, a następnie, gdy spełniony zostanie powyższy warunek, przełączymy stan, dając mu sygnał do pobierania, uzależniając nasz pierwszy hook od wartości stanu.

const [loadMore, setLoadMore] = useState(false);
useEffect(() => {
  setLoadMore(false);
  getData();
}, [loadMore]);


Możemy również warunkowo renderować spinner ładujący na dole, czekając na odpowiedź API, inicjując nowy stan z pewną wartością prawdziwą, a następnie resetując go, gdy żądanie zostanie spełnione.

Ponadto, aby uniknąć potencjalnych błędów, możemy usunąć listenera zdarzeń z obiektu okna, gdy komponent zostanie odmontowany, dodając instrukcję zwrotną w useEffect w ten sposób:

useEffect(() => {
  widnow.addEventListener('event', function);
  return () => {
    window.removeEventListener('event', function);
  }
}, [])


Linki

Demo na żywo | Repozytorium

Dzięki za przeczytanie i miłego kodowania!


Oryginał tekstu w języku angielskim przeczytasz tutaj.

Lubisz dzielić się wiedzą i chcesz zostać autorem?

Podziel się wiedzą z 130 tysiącami naszych czytelników

Dowiedz się więcej