使用 redux 无限滚动
Infinite scrolling with redux
我遇到了这个问题。
我的后端有一个调用,它 returns 根据请求的页面为我提供了一个元素数组,为简单起见,假设它的结构如下
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);
}
};
最后是我的 reducer,它只是将值分配给我的初始帖子状态,如下所示:
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}
]
显然一切都会爆炸。我怎样才能做到这一点?有更好的方法吗?提前感谢谁会回答我。
我已经解决了这个问题,但我不知道这是否是一个很好的解决方案:
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);
}
};
您的 GET_POSTS
操作不需要包含整个帖子数组,包括那些已经处于该状态的帖子。您可以分派一个动作,其中包含页面的帖子数组和当前页码。 if (page === 1)
逻辑最好在 reducer 中处理。
我建议您分派一个操作,其中 payload
是一个具有属性 posts
和 page
的对象。但是看看你的减速器,你的 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
的值。
我遇到了这个问题。
我的后端有一个调用,它 returns 根据请求的页面为我提供了一个元素数组,为简单起见,假设它的结构如下
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);
}
};
最后是我的 reducer,它只是将值分配给我的初始帖子状态,如下所示:
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}
]
显然一切都会爆炸。我怎样才能做到这一点?有更好的方法吗?提前感谢谁会回答我。
我已经解决了这个问题,但我不知道这是否是一个很好的解决方案:
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);
}
};
您的 GET_POSTS
操作不需要包含整个帖子数组,包括那些已经处于该状态的帖子。您可以分派一个动作,其中包含页面的帖子数组和当前页码。 if (page === 1)
逻辑最好在 reducer 中处理。
我建议您分派一个操作,其中 payload
是一个具有属性 posts
和 page
的对象。但是看看你的减速器,你的 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
的值。