【问题标题】:Infinite scrolling with redux使用 redux 无限滚动
【发布时间】:2021-12-20 17:38:55
【问题描述】:

我遇到了这个问题。

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

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}
]

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

【问题讨论】:

    标签: reactjs redux infinite-scroll payload


    【解决方案1】:

    我已经解决了这个问题,但我不知道是否是一个很好的解决方案:

    export const getPosts = (page) => async (dispatch) => {
      try {
        const { data } = await api.fetchPosts(
          page,
          store.getState().auth.user?._id
        );
    
        console.log("page action ==> ", page);
        // console.log("THIS IS DATA ==> ", data.data);
    
        if (page === 1) {
          dispatch({
            type: START_LOADING,
          });
          dispatch({
            type: GET_POSTS,
            payload: data,
          });
        } else {
          let newpayload = store.getState().posts.posts;
          data.data.map((item) => {
            return newpayload.push(item);
          });
        }
    
        dispatch({
          type: END_LOADING,
        });
      } catch (error) {
        console.log(error);
      }
    };
    

    【讨论】:

    • 你正在用 .push 改变你的状态,所以这不是一个好的解决方案。你想发送一个包含帖子和页码的操作,并让 reducer 找出放置它们的位置。
    【解决方案2】:

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

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

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

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

    reducer 的工作是根据页码找出要做什么。

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

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

    【讨论】:

    • 这对我来说是完美的解决方案。它比我采用的解决方案干净得多。我已经将逻辑转移到了 reducer,但是当解决方案出现时,我遇到了奇怪的逻辑。非常感谢您的帮助!
    猜你喜欢
    • 2022-07-12
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 2015-01-13
    • 2019-11-23
    • 1970-01-01
    相关资源
    最近更新 更多