React.js: Как создать функцию loadMore onClick?

#javascript #reactjs

Вопрос:

Я пытаюсь реализовать небольшое приложение с loadMore кнопкой.
По умолчанию он должен выводить 3 данных и показывать еще 3 данных каждый раз, когда пользователь нажимает кнопку загрузить больше.
Попробовав несколько способов, я пришел к этому решению, предложенному в этой статье.
Вот ссылка codesandox

App.js

   let arrayForHoldingStories = [];
  const [topStoryIds] = useStories();
  const [storiesToShow, setStoriesToShow] = useState([]);
  const [next, setNext] = useState(3);

  const loopWithSlice = (start, end) => {
    const slicedStories = topStoryIds.slice(start, end);
    arrayForHoldingStories = [...arrayForHoldingStories, ...slicedStories];
    setStoriesToShow([...arrayForHoldingStories, ...slicedStories]);
  };

  useEffect(() => {
    loopWithSlice(0, storiesPerPage);
  }, [topStoryIds]);

  const handleShowMorePosts = () => {
    let loadedMore = next   storiesPerPage;
    loopWithSlice(next, loadedMore);
    setNext(next   storiesPerPage);
  };
 

Но проблема в том, что при объединении исходного массива и нового массива у них одинаковые элементы, и это приводит к ошибке

 Warning: Encountered two children with the same key, `26991887`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
 

Я попытался удалить дубликаты из обоих массивов с помощью forEach set функций или перед объединением, но это тоже не сработало.
Моя попытка

   const loopWithSlice = (start, end) => {
    const slicedStories = topStoryIds.slice(start, end);
    arrayForHoldingStories = [...arrayForHoldingStories, ...slicedStories];

    setStoriesToShow([...arrayForHoldingStories, ...slicedStories]); //it throws mentioned error  
    /* slicedStories.forEach((uniqueId) => { //this will also throw same error
      arrayForHoldingStories.forEach((addedId) => {
        if (uniqueId !== addedId) {
          setStoriesToShow([...slicedStories, ...arrayForHoldingStories]);
        }
      });
    }); */

    /*   setStoriesToShow([   //this will also throw same error
      ...new Set([...arrayForHoldingStories, ...slicedStories])
    ]); */
  };
 

Любая помощь будет оценена по достоинству.

Ответ №1:

Согласно вашему описанию, вам не нужно иметь аргументы конца или начала для вашего цикла с функцией среза. Вы можете использовать длину storiesToShow состояния

 import React, { useState, useEffect } from "react";

import Stories from "./Stories";
import useStories from "./hooks/useStories";

function App() {
  const storiesPerPage = 3;
  let arrayForHoldingStories = [];
  const [topStoryIds] = useStories();
  const [storiesToShow, setStoriesToShow] = useState([]);
  const [next, setNext] = useState(3);

  const loopWithSlice = () => {
    const toShow = topStoryIds.slice(
      storiesToShow.length,
      storiesToShow.length   storiesPerPage
    );
    setStoriesToShow([...storiesToShow, ...toShow]);
  };

  useEffect(() => {
    if (topStoryIds) {
      loopWithSlice();
    }
  }, [topStoryIds]);

  const handleShowMorePosts = () => {
    let loadedMore = next   storiesPerPage;
    loopWithSlice(next, loadedMore);
    setNext(next   storiesPerPage);
  };

  console.log("next", next);
  console.log("storiesPerPage", storiesPerPage);
  console.log("loopWithSlice", loopWithSlice);
  console.log("arrayForHoldingStories", arrayForHoldingStories);
  console.log("storiesToShow", storiesToShow);

  return (
    <>
      <div>
        {storiesToShow.length > 0 amp;amp;
          storiesToShow.map((storyId) => (
            <Stories storyId={storyId} key={storyId} />
          ))}
      </div>
      <button onClick={handleShowMorePosts}>load more</button>
    </>
  );
}

export default App;
 

Вы можете проверить sanbox здесь для получения полного кода.

Комментарии:

1. Привет @Джош, большое тебе спасибо. В этом есть большой смысл.

2. Привет @Josh, еще раз спасибо за ответ. Не могли бы вы, пожалуйста, ответить еще на один вопрос? Несмотря на то, что ваше решение работает нормально, и это незначительная вещь, но я хотел бы понять и решить предупреждение useEffect, в котором говорится: У React Hook useEffect отсутствует зависимость: «loopWithSlice». Либо включите его, либо удалите массив зависимостей. (реагирующие крючки/исчерпывающие депы)eslint» . Если я удалю массив зависимостей, приложение выйдет из строя. Каким было бы лучшее решение, чтобы избавиться от этого предупреждения? Заранее благодарю

3. @Greg это связано с вызовом loopWithSlice начального рендеринга, который создает своего рода шаблон подписки для useEffect . Также loopWithSlice функция может меняться между визуализациями, поэтому это правило гарантирует, что функция будет включена в массив deps в случае ее изменения. Я изменил песочницу, чтобы показать лучший способ без вызова loopWithSlice начального рендеринга.

4. Привет @Josh, еще раз спасибо за вашу помощь. Я понял.