首页 > 解决方案 > 使用 redux 无限滚动

问题描述

我面临这个问题。

我在后端有一个调用,它根据请求的页面返回一个元素数组,为简单起见,假设它的结构如下

export const fetchPosts = (page) => API.get(`/posts?page=${page}`)

现在在我的操作中,当页面加载时,我只需调用我的端点(默认页面为 1)并获取我的帖子。这样 :

export const getPosts = (page) => async (dispatch) => {
  try {
    
    dispatch({
      type: START_LOADING,
    });
    const { data } = await api.fetchPosts(
      page,
      store.getState().auth.user?._id
    );
      
    dispatch({
      type: GET_POSTS,
      payload: data,
    });
    dispatch({
      type: END_LOADING,
    });
  } catch (error) {
    console.log(error);
  }
};

最后是我的减速器,它只是将值分配给我的初始帖子状态,如下所示:

const initialState = {
  posts: [],
  currentPage: null,
  numberOfPages: null,
  isLoading: true,
  post: {},
  postsOfCurrentUser: [],
};



case GET_POSTS:
      return {
        posts: payload.data,
        currentPage: payload.currentPage,
        numberOfPages: payload.numberOfPages,
        post: {},
      };

现在,我想做的是,当您按下按钮或滚动时,会向我的后端发出一个新调用,并传递新页面,到目前为止没有问题。当我想修改过去的有效负载时,问题就出现了,为简单起见,我们假设是这样的:初始页面加载时的帖子:

[{title : 1} , {title:2} , {title:3}]

按下按钮或滚动后,我希望它是:

[{title : 1} , {title:2} , {title:3},{title : 4} , {title:5} , {title:6}]

所以我在我的行动中尝试了这样的:

export const getPosts = (page) => async (dispatch) => {
  try {
    dispatch({
      type: START_LOADING,
    });
    const { data } = await api.fetchPosts(
      page,
      store.getState().auth.user?._id
    );
    if (page === 1) {
      dispatch({
        type: GET_POSTS,
        payload: data,
      });
    } else {
      dispatch({
        type: GET_POSTS,
        payload: [...store.getState().posts.posts, data],
      });
    }

    dispatch({
      type: END_LOADING,
    });
  } catch (error) {
    console.log(error);
  }
};

但我得到的是:

[
   [
      {title : 1} , {title:2} , {title:3}
   ]
   ,{title : 4} , {title:5} , {title:6}
]

显然一切都会爆炸。我怎样才能做到这一点?有没有更好的方法?提前感谢谁会回答我。

标签: reactjsreduxinfinite-scrollpayload

解决方案


您的GET_POSTS操作不需要包含整个帖子数组,包括那些已经处于状态的帖子。您可以调度一个包含页面帖子数组和当前页码的操作。逻辑是在if (page === 1)减速器中处理得更好的东西。

我将建议您调度一个动作,其中payload是一个具有属性postspage. 但是看看你的 reducer,你的 API 中的变量似乎已经在属性data中包含了该信息。.currentPage因此,您可以删除添加到操作创建器的所有额外逻辑,然后返回到您发布的第一个版本,所有页面都调度相同的操作:

dispatch({
  type: GET_POSTS,
  payload: data
});

createAsyncThunk(您可以使用Redux Toolkit中的函数使您的 thunk 操作更加简洁。)

根据页码确定要做什么是减速器的工作。

case GET_POSTS:
  const { data, currentPage, numberOfPages } = payload;
  return {
     ...state,
     posts: currentPage === 1 ? data : [...state.posts, ...data]
     currentPage,
     numberOfPages
  };

我正在使用三元运算符来替换整个帖子数组或添加到现有数组中,具体取决于currentPage.


推荐阅读