【问题标题】:Infinite Scroll doesn't keep previous items in React/ReduxInfinite Scroll 不会在 React/Redux 中保留以前的项目
【发布时间】:2022-01-18 15:26:09
【问题描述】:

当用户滚动到页面底部时,我正在尝试通过无限滚动从 reddit API 加载第二组项目,尽管它们确实加载成功,但之前的项目会被新项目覆盖。

您可以在这里看到这种情况:https://reddix.netlify.app/

这是带有 Thunks 的 Redux Slice:

// Gets the first 10 Posts from the API
export const getPosts = createAsyncThunk(
  "post/getPosts",
  async (apiAddress) => {
    const response = await fetch(apiAddress);
    if (!response.ok) throw new Error("Request Failed!");
    const data = await response.json();
    return data;
  }
);

// Loads the Next 10 Posts
export const getMorePosts = createAsyncThunk(
  "post/getMorePosts",
  async (apiAddress) => {
    const response = await fetch(apiAddress);
    if (!response.ok) throw new Error("Request Failed!");
    const data = await response.json();
    return data;
  }
);

const redditPostSlice = createSlice({
  name: "post",
  initialState: {
    redditPost: {},
    isLoading: false,
    hasError: false,
    moreIsLoading: false,
    moreHasError: false,
  },
  extraReducers: (builder) => {
    builder
      .addCase(getPosts.pending, (state) => {
        state.isLoading = true;
        state.hasError = false;
      })
      .addCase(getPosts.fulfilled, (state, action) => {
        state.redditPost = action.payload.data;
        state.isLoading = false;
        state.hasError = false;
      })
      .addCase(getPosts.rejected, (state) => {
        state.isLoading = false;
        state.hasError = true;
      })
      .addCase(getMorePosts.pending, (state) => {
        state.moreIsLoading = true;
        state.moreHasError = false;
      })
      .addCase(getMorePosts.fulfilled, (state, action) => {
        state.redditPost = action.payload.data;
        state.moreIsLoading = false;
        state.moreHasError = false;
      })
      .addCase(getMorePosts.rejected, (state) => {
        state.moreIsLoading = false;
        state.moreHasError = true;
      });
  },
});

在这个搜索组件中,我有加载页面的功能:

const Search = () => {
  const [input, setInput] = useState("");
  const [isFetching, setIsFetching] = useState(false);
  const redditPost = useSelector(selectRedditPost);
  const dispatch = useDispatch();

  // Get the Last Post
  const lastPost = () => {
    if (redditPost.children) {
      const [lastItem] = redditPost.children.slice(-1);

      const lastKind = lastItem.kind;
      const lastId = lastItem.data.id;

      return `${lastKind}_${lastId}`;
    } else {
      return;
    }
  };

  // API Endpoints
  const hotApiAddress = `https://www.reddit.com/r/${input}/hot.json?limit=10`;
  const newApiAddress = `https://www.reddit.com/r/${input}/new.json?limit=10`;
  const moreApiAddress = `https://www.reddit.com/r/${input}/new.json?limit=10&after=${lastPost()}`;

  // Get Hot Posts
  const handleHot = (e) => {
    e.preventDefault();
    if (!input) return;

    dispatch(getPosts(hotApiAddress));
  };

  // Get New Posts
  const handleNew = (e) => {
    e.preventDefault();
    if (!input) return;

    dispatch(getPosts(newApiAddress));
  };

  // Fire Upon Reaching the Bottom of the Page
  const handleScroll = () => {
    if (
      window.innerHeight + document.documentElement.scrollTop !==
      document.documentElement.offsetHeight
    )
      return;

    setIsFetching(true);
  };

  // Debounce the Scroll Event Function and Cancel it When Called
  const debounceHandleScroll = debounce(handleScroll, 100);

  useEffect(() => {
    window.addEventListener("scroll", debounceHandleScroll);
    return () => window.removeEventListener("scroll", debounceHandleScroll);
  }, [debounceHandleScroll]);

  debounceHandleScroll.cancel();

  // Get More Posts
  const loadMoreItems = useCallback(() => {
    dispatch(getMorePosts(moreApiAddress));
    setIsFetching(false);
  }, [dispatch, moreApiAddress]);

  useEffect(() => {
    if (!isFetching) return;
    loadMoreItems();
  }, [isFetching, loadMoreItems]);

有没有办法在下一组加载时保留以前的项目?

【问题讨论】:

标签: javascript reactjs redux react-redux infinite-scroll


【解决方案1】:

因为您在每次调度时都设置了不同的有效负载值,所以您之前的数组会消失。看看entityAdapter。有了这个适配器,您可以轻松管理数组,您可以添加、修改、更新或删除数组中的项目。这可以为您提供解决方案。 将前一个值保存在列表中,并在调度下一个操作时,附加现有列表。

注意:您需要entityAdapter 上的upsertMany 方法来保留以前的值。

没有entityAdapter的其他解决方案: 您必须以某种方式将数组存储在状态中,因为当另一个有效负载出现时,您必须访问此数组,例如state.redditPosts = [...state.redditPosts, ...payload.array]。或者因为你使用redux js 工具包,所以可以改变状态,state.redditPosts.push(...payload.array)

【讨论】:

  • 我会检查的。谢谢!问题是我的有效载荷中没有数组。它实际上是一个对象,只有一个值是我在别处访问的子数组。
  • 我试图理解 entityAdapter 但根本无法让它工作。有没有其他方法可以做到这一点?
  • 我更新了答案。
  • 感谢您的更新。不幸的是,它没有帮助我。我已经从我提出的另一个问题中找到了答案,并将在问题的评论部分包含链接。
  • 是的,这就是我想说的:)
猜你喜欢
  • 2020-11-15
  • 1970-01-01
  • 2020-11-14
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-07
相关资源
最近更新 更多