【问题标题】:How to properly paginate data in React with Firestore?如何在 React with Firestore 中正确分页数据?
【发布时间】:2019-10-31 03:13:21
【问题描述】:

当我开始使用 Firebase 时,我有点为博客网站上的帖子分页而苦苦挣扎:(。

我想我有点理解来自 Google 的文档,并且我知道如何将分页移到下一页。但是,我完全不知道如何分页返回上一页。

基本上,我想要一个简单的分页组件,它看起来像这样:(您可以在其中使用箭头进行分页和返回)。

分页到下一页很好,但是当涉及到分页时,我找不到任何合适的教程来用纯 React 来做。

我尝试使用 startAt、endAt、endBefore 等各种方法。但结果是错误或将我移回第一页(即使我在第三或第四页)

我什至尝试在数组中找到第一个对象并将其用作 endBefore,但它再次导致分页返回到第一页。

这就是我的代码现在的样子(是的,我知道 pageNext() 和 pagePrev() 是一样的)

import React, { Component } from 'react'
import { withFirebase } from './Firebase'
import Post from './Post'

import '../scss/Post.scss'

class Posts extends Component {
    constructor(props) {
        super(props);
        this.state = {
            loading:false,
            posts:[],
            post_id:[],
            lastVisible:null,
            limit:2
        }

        this.handlePageNext = this.handlePageNext.bind(this);
    }
    componentDidMount() {
        let newPosts=[];
        let postsId=[];

        this.setState({ loading: true });

        this.props.firebase.posts()
        .orderBy('date', 'desc')
        .limit(2)
        .get().then(querySnapshot => {
            let lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
            this.setState({ lastVisible: lastVisible});

            querySnapshot.forEach(doc => {
                newPosts = newPosts.concat(doc.data());
                postsId = postsId.concat(doc.id);           
                this.setState({
                    posts:newPosts,
                    post_id:postsId,
                    loading:false
                });
            })
        })



    }

    handlePageNext() {
        let newPosts=[];
        let postsId=[];

        this.setState({ loading: true });

        this.props.firebase.posts()
        .orderBy('date', 'desc')
        .startAt(this.state.lastVisible)
        .limit(this.state.limit)
        .get().then(querySnapshot => {
            let lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];

            this.setState({ lastVisible:lastVisible });
            querySnapshot.forEach(doc => {
                newPosts = newPosts.concat(doc.data());
                postsId = postsId.concat(doc.id);           
                this.setState({
                    posts:newPosts,
                    post_id:postsId,
                    loading:false
                });
            })
        })
    }

    handlePagePrev() {
        let newPosts=[];
        let postsId=[];

        this.setState({ loading: true });

        this.props.firebase.posts()
        .orderBy('date', 'desc')
        .startAt(this.state.lastVisible)
        .limit(this.state.limit)
        .get().then(querySnapshot => {
            let lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];

            this.setState({ lastVisible:lastVisible});
            querySnapshot.forEach(doc => {
                newPosts = newPosts.concat(doc.data());
                postsId = postsId.concat(doc.id);           
                this.setState({
                    posts:newPosts,
                    post_id:postsId,
                    loading:false
                });
            })
        })
    }

    render() {
        return (
            <div className='posts'>
                <div className='row'>
                    {this.state.posts.map((post, i) => (
                        <Post 
                            key={i}
                            title={post.title}
                            author={post.author}
                            desc={post.desc}
                            text={post.text}
                            id={this.state.post_id[i]}
                            date={post.date}
                            imgURL={post.imgURL}/>
                    ))}

                    {this.state.loading && <p>Loading...</p>}
                    <button className='btn' onClick={() => this.handlePagePrev()}>&larr;</button>
                    <button className='btn' onClick={() => this.handlePageNext()}>></button>

                </div>

            </div>
        )
    }
}

export default withFirebase(Posts);

我想使用按钮(左右箭头)进行简单的分页,但我已经为此苦苦挣扎了 3 个小时,找不到合适的解决方案。

【问题讨论】:

  • 懂Android的可以看看here

标签: reactjs firebase pagination google-cloud-firestore


【解决方案1】:

您必须保留“lastVisible”并将其传递给 startAfter()。我在下面写的 2 个函数:

export const getMostRecentPostsFirstPage = (limit, specificUserId) => {
  if (!Number.isInteger(limit) || limit < 1) {
    throw new Error('limit must be a positive integer');
  }

  const collection = Firestore.collection('posts');
  let query = null;

  if (specificUserId) {
    query = collection
      .where('userId', '==', `${specificUserId}`)
      .orderBy('postedTimestamp', 'desc')
      .limit(limit);
  } else {
    query = collection.orderBy('postedTimestamp', 'desc').limit(limit);
  }

  return new Promise((resolve, reject) => {
    const posts = [];
    query
      .get()
      .then(snapshot => {
        const lastVisible = snapshot.docs[snapshot.docs.length - 1];
        snapshot.forEach(post => {
          posts.push(post.data());
        });
        const hasMore = posts.length == limit;
        resolve({ posts: posts, lastVisible: lastVisible, hasMore: hasMore });
      })
      .catch(error => reject(error));
  });
};
export const getMostRecentPostsNextPage = (lastVisible, limit, specificUserId) => {
  if (!lastVisible) {
    throw new Error('Need to provide lastVisible argument');
  }

  if (!Number.isInteger(limit) || limit < 1) {
    throw new Error('limit must be a positive integer');
  }

  const collection = Firestore.collection('posts');
  let query = null;

  if (specificUserId) {
    query = collection
      .where('userId', '==', `${specificUserId}`)
      .orderBy('postedTimestamp', 'desc')
      .startAfter(lastVisible)
      .limit(limit);
  } else {
    query = collection
      .orderBy('postedTimestamp', 'desc')
      .startAfter(lastVisible)
      .limit(limit);
  }

  return new Promise((resolve, reject) => {
    const posts = [];
    query
      .get()
      .then(snapshot => {
        const lastVisible = snapshot.docs[snapshot.docs.length - 1];
        snapshot.forEach(post => {
          posts.push(post.data());
        });
        const hasMore = posts.length == limit;
        resolve({ posts: posts, lastVisible: lastVisible, hasMore: hasMore });
      })
      .catch(error => reject(error));
  });
};

它使用 redux-saga,但你明白了。

在第一次查询时,不要调用“startAfter()”,但在随后的查询中,必须在每次调用之间保存“lastVisible”。

【讨论】:

  • 感谢您的帮助,我将尝试自己管理它,如果我无法做到,我将简单地实现一个按钮来查看旧帖子。
  • 在我的例子中,这不是实际的分页,它是为了实现无限滚动,所以要查看用户只是向上滚动的旧帖子。祝你好运,不要放弃!
  • 我想我会使用无限滚动,它是由按钮激活的,因为我找不到返回上一页的解决方案。有查询和 limitToLast 方法,我会尝试更深入地挖掘,但我认为这种情况会在无限滚动方面做得最好,因为它只是为了学习目的:P
【解决方案2】:

Here 是在 reactjs 中使用 Firebase 的标准分页。

【讨论】:

  • 哦,太好了!即使我曾经以本教程为基础,我也没有注意到这一点。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-11-07
  • 1970-01-01
  • 2020-01-26
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多