使用 React 和 Redux 对来自 API 的特定日期结果进行分页
Posted
技术标签:
【中文标题】使用 React 和 Redux 对来自 API 的特定日期结果进行分页【英文标题】:Paginate date-specific results from an API with React and Redux 【发布时间】:2018-02-24 10:19:34 【问题描述】:我想使用 Redux 在我的 React 应用中显示一些新闻。
问题是我想显示个别日期的新闻并且我想对新闻进行分页。
在我的 API 中打印
pagination:
count: 1000,
size: 10,
page: 1,
pages: 100
,
news: [
..
]
我知道如何进行简单的分页,但如果我希望能够在我的应用中显示不同日期的新闻,我不知道 API 应该如何工作。
到目前为止(没有日期),我只是在我的 Redux reducer 中保留了一个状态 news
和 pagination
,然后检查页码是否等于总页数以确定是否应该尝试加载更多新闻.
但现在我可能有许多不同的日期,我想将所有新闻都保存在 Redux 商店中,我不知道如何组织它。
我可以保持 API 不变,因为使用 GET 参数?date=15-09-2017
进行过滤只会减少 API 结果中的新闻数量。
但是是否仍然可以将所有新闻保存在我的 reducer 中的 news
变量中的数组中,或者我是否必须将其结构化为类似
news:
'15-09-2017':
news: [...],
pagination:
,
...
为了跟踪每个日期的分页?
【问题讨论】:
您的意思是每个日期还需要单独的页面吗? 我需要能够按“加载更多”,然后将新闻附加到每个日期的已加载新闻中 【参考方案1】:一种结构,您可以通过 id 和每个日期的 id 来存储您的新闻,这将是一种很好且灵活的结构:
"byId":
"10": /* News */ ,
"14": /* News */ ,
/* ... */
,
"listsByDate":
"2017-08-24":
"total": 100,
"pageSize": 10,
"page": 2,
"items": [
10,
14,
/* ... */
]
您可以为此结构实现简单的选择器:
const getNewsById = (state, id) => state.byId[id];
const getListByDate = (state, date) => state.listByDate[date];
const getPageOfList = (state, data) => getListByDate(state, date).page
/* ... */
const getNewsByDate = (state, date) =>
return getListByDate(state, data).items.map((id) =>
return getNewsById(state, id);
);
【讨论】:
谢谢。如何在 reducer 中将新闻附加到listsByDate[date].items
?
因为 redux 不希望对象发生突变,所以您必须创建一个新数组。您只需使用newArr = [].concat(oldArray, [ newItemToAppend ]);
即可。【参考方案2】:
我建议将所有新闻保存在一个地方(news
在你的 reducer 中),并使用selectors 来计算派生数据。
要实现这一点,您需要将当前日期(我想它是您应用中的某种过滤器)存储在 Redux 商店中,以便在您的选择器中使用。
所以你的减速器看起来像:
news: [], // you can keep all the news here
date: '15-09-2017', // selected date
page: 1, // current page
pagination:
'15-09-2017': ... , // pagination info by date.
// You will need this only if you use the classic pager (with page numbers in UI)
// it's not needed in case of infinite scroll
和选择器:
import createSelector from 'reselect';
// select all news
const newsSelector = () => (state) => state.get('news');
// select date
const dateSelector = () => (state) => state.get('date');
// select page
const pageSelector = () => (state) => state.get('page');
// select news by date
const newsByDateSelector = () => createSelector(
newsSelector(),
dateSelector(),
(news, date, page) => news.filter((newsItem) => newsItem.get('date') === date)
);
const pageSize = 10;
const newsByDatePagedSelector = () => createSelector(
newsByDateSelector(),
pageSelector(),
(news, page) => news.slice(pageSize * (page - 1), pageSize * page)
);
然后您可以使用newsByDatePagedSelector
选择器在您的容器中获取所需的新闻:
import React from 'react';
import connect from 'react-redux';
import createStructuredSelector from 'reselect';
export class NewsContainer extends React.PureComponent
componentDidMount()
// news by selected date are not loaded yet
if (!this.props.news)
this.loadNews();
componentWillReceiveProps(nextProps)
// user navigated to the next page
if (this.props.news && !nextProps.news)
this.loadNews();
loadNews()
// fetch next 10 news from server
render()
return (
<div>
this.props.news.map((newsItem) => ...)
</div>
);
const mapStateToProps = createStructuredSelector(
news: newsByDatePagedSelector(),
);
export default connect(mapStateToProps)(NewsContainer);
当用户在某个日期到达最后一条新闻时,您可以像往常一样使用过滤器?date=15-09-2017
从您的 API 中请求接下来的 10 条新闻并将它们放到您的商店中。 Redux 和 reselect 会将它们带到 NewsContainer
作为 newsByDate
属性。
【讨论】:
但是如何保留页码呢?如果我在一个页面上继续单击加载更多,直到我在第 10 页,总共有 100 (10 * 10) 条新闻,那么如果我去另一个日期,我将不得不将页码重置为 1 以加载第一个当天有 10 条新闻。但是现在如果我回到第一个日期,我不想加载前 100 条新闻,因为我已经加载了这些? 对不起,一开始我错过了关于分页的部分。我更新了答案 我不需要常规的页码分页,但是我仍然不知道如何确定是否有更多页面需要加载以确保我不会调用API加载完所有内容后 另外,如何更改页码?我应该做一个获取新新闻并设置页码的 redux 操作吗?还是应该单独设置页码?以上是关于使用 React 和 Redux 对来自 API 的特定日期结果进行分页的主要内容,如果未能解决你的问题,请参考以下文章
Laravel API 不允许我的前端使用 React 和 Redux 访问
如何在 React/Redux 中获取和传递对象(JSON API)?
使用redux,如何避免在进行新的API调用之前渲染旧的状态数据?
如何使用来自 react-redux-firebase 的 redux thunk getFireBase 和 getFirestore 将数据添加到 firebase doc