最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Paginate date-specific results from an API with React and Redux - Stack Overflow

programmeradmin0浏览0评论

I want to show some news in my React app using Redux.

The problem is that I want to show the news for individual dates and I want to paginate the news.

In my API I print

{
  pagination: {
    count: 1000,
    size: 10,
    page: 1,
    pages: 100
  },
  news: [
    ..
  ]
}

I know how to make a simple pagination, but I don't know how the API should work if I want to be able to show news for different dates in my app.

Until now (without dates), I have just kept a state news and pagination in my Redux reducer, and then checked if the page number equals the total number of pages to determine whether it should try loading more news.

But now that I potentially have many different dates and I want to keep all the news in the Redux store, I don't know how to structure it.

I can keep my API as it is, since filtering with GET parameter ?date=15-09-2017 will just decrease the number of news in the API result.

But would it still be possible to just keep all the news in an array in a news variable in my reducer or do I have to structure it to be something like

news: {
  '15-09-2017': {
    news: [...],
    pagination: {}
  },
  ...
}

in order to keep track of the pagination for every single date?

I want to show some news in my React app using Redux.

The problem is that I want to show the news for individual dates and I want to paginate the news.

In my API I print

{
  pagination: {
    count: 1000,
    size: 10,
    page: 1,
    pages: 100
  },
  news: [
    ..
  ]
}

I know how to make a simple pagination, but I don't know how the API should work if I want to be able to show news for different dates in my app.

Until now (without dates), I have just kept a state news and pagination in my Redux reducer, and then checked if the page number equals the total number of pages to determine whether it should try loading more news.

But now that I potentially have many different dates and I want to keep all the news in the Redux store, I don't know how to structure it.

I can keep my API as it is, since filtering with GET parameter ?date=15-09-2017 will just decrease the number of news in the API result.

But would it still be possible to just keep all the news in an array in a news variable in my reducer or do I have to structure it to be something like

news: {
  '15-09-2017': {
    news: [...],
    pagination: {}
  },
  ...
}

in order to keep track of the pagination for every single date?

Share Improve this question asked Sep 15, 2017 at 9:10 JamgreenJamgreen 11.1k32 gold badges122 silver badges231 bronze badges 2
  • Do you mean you also need separate page for each date? – vtambourine Commented Sep 23, 2017 at 18:09
  • I need to be able to press "load more" and then append the news to the already-loaded news for every single date – Jamgreen Commented Sep 23, 2017 at 19:38
Add a ment  | 

2 Answers 2

Reset to default 8 +150

A think a structure where you store your your news by id and ids per date would be good and flexible structure:

{
    "byId": {
        "10": { /* News */ },
        "14": { /* News */ },
        /* ... */
    },
    "listsByDate": {
        "2017-08-24": {
            "total": 100,
            "pageSize": 10,
            "page": 2,
            "items": [
                10,
                14,
                /* ... */
            ]
        }
    }
}

You can implement simple selectors for this structure:

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);
    });
}

I would remend to keep storing all news in a single place (news in your reducer), and use selectors to pute derived data.

To achieve this, you will need to store the current date (I suppose it's a some kind of filter in your app) in Redux store, so it can be used in your selector.

So your reducer will look like:

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

And selectors:

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)
);

Then you can use newsByDatePagedSelector selector to get the needed news in your container:

import React from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';

export class NewsContainer extends React.PureComponent {
  ponentDidMount() {
    // news by selected date are not loaded yet
    if (!this.props.news) {
      this.loadNews();
    }
  }

  ponentWillReceiveProps(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);

When user reach the last news by some date, you can request next 10 news from your API as usual with filter ?date=15-09-2017 and put them to your store. Redux and reselect will bring them to NewsContainer as newsByDate prop.

发布评论

评论列表(0)

  1. 暂无评论