如何使用ReactJs对Cloud Firestore数据进行分页

时间:2018-10-29 11:42:21

标签: javascript reactjs firebase google-cloud-firestore

我正在使用Firebase-Cloud Firestore,目前我想对所有可用记录进行分页。我已经有记录列表了,剩下的就是一些分页了。我是Cloud Firestore的新手,因此感谢您提供任何清晰度。

我使用ReactJS查看了Firestore文档(https://firebase.google.com/docs/firestore/query-data/query-cursors#paginate_a_query)和示例,但是没有太多可用。

我理解例如:.startAt(0), .limit(10),但问题是如何使用render方法调用的该组件正确地分页。

import React, { Component } from 'react';
import Pagination from "react-js-pagination";
import firestore from "./Firebase";

export default class DataList extends Component {

constructor(props) {
    super(props);
    this.state = {
        dbItems: [],
        currentPage: 1,
        itemsPerPage: 3,
        totalItemCount: 1,
        activePage: 15
    }
    this.handlePageChange = this.handlePageChange.bind(this);
}

handlePageChange(pageNumber) {
    console.log(`active page is ${pageNumber}`);
    this.setState({ activePage: pageNumber });
}

async getItems() {
    const { currentPage, itemsPerPage } = this.state;
    const startAt = currentPage * itemsPerPage - itemsPerPage;
    const usersQuery = firestore.collection('Users').orderBy("email").startAt(startAt).limit(itemsPerPage)
    const snapshot = await usersQuery.get()
    const items = snapshot.docs.map(doc => doc.data())
    return this.setState({ 
        dbItems: items,
        totalItemCount: firestore.collection('Users').get().then(res => console.log(res.size))
    })

}

componentDidMount() {
    this.getItems()
}

componentDidUpdate(prevProps, prevState) {
    const isDifferentPage = this.state.currentPage !== prevState.currentPage
    if (isDifferentPage) this.getItems()
}

render() {
    return (
        <div>
            {this.state.dbItems.map((users, index) => {
                return (
                    <p key={index}>
                        <b>First Name:</b> {users.firstname} <br />
                        <b>Email:</b> {users.email}
                    </p>
                )
            })
            }
            <Pagination
                activePage={this.state.activePage}
                itemsCountPerPage={this.state.itemsPerPage}
                totalItemsCount={this.state.totalItemCount}
                pageRangeDisplayed={this.state.itemsPerPage}
                onChange={this.handlePageChange}
            />
        </div>
    )
}
}

谢谢您的帮助!

4 个答案:

答案 0 :(得分:4)

使用startAt()

可以实现分页
// Get Items.
async getItems() {
  const {currentPage, itemsPerPage} = this.state
  const startAt = currentPage * itemsPerPage - itemsPerPage
  const query = firestore.collection('Users').startAt(startAt).limit(itemsPerPage)
  const snapshot = await query.get()
  const items = snapshot.docs.map(doc => doc.data())
  return this.setState({dbItems: items})
}

// Did Mount.
componentDidMount() {
  this.getItems()
}

// Did Update.
componentDidUpdate(prevProps, prevState) {
  const isDifferentPage = this.state.currentPage !== prevState.currentPage
  if (isDifferentPage) this.getItems()
}

答案 1 :(得分:3)

FirestoreFirestore PaginationReactJS陌生的任何人都很难理解分页的工作方式或何时触发对Firestore中下一组文档的调用。像这样挣扎的任何人都可以尝试我的示例来提出一些想法并向前进行。(我使用React-Bootstrap来呈现UI元素)

01-安装软件包react-infinite-scroll-component

首先安装此软件包yarn add react-infinite-scroll-component

02-包含软件包

通过'import InfiniteScroll from 'react-infinite-scroll-component';'导入将其包含到文件中

03-初始化状态

使用空列表数组初始化状态

this.state = {
    list: [],
};

04-创建函数以获取第一组数据并使用安装了组件的组件进行初始化

//component did mount will fetch first data from firestore 
componentDidMount(){
    this.getUsers()
}

getUsers(){
  let set = this
  //initiate first set
  var first = set.ref.collection("users").limit(12);
  first.get().then(function (documentSnapshots) {
    // Get the last visible document
    var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
    //initiate local list 
    const list = [];
    documentSnapshots.forEach(function(doc) {
        //im fetching only name and avatar url you can get any data 
        //from your firestore as you like
        const { name, avatar_full_url } = doc.data();
        //pushing it to local array
        list.push({ key: doc.id, name, avatar_full_url });
    });
        //set state with updated array of data 
        //also save last fetched data in state
        set.setState({ list, last: lastVisible });
    });
}

05-创建获取余额数据集的功能

fetchMoreData = () => {
  let set = this
  //get last state we added from getUsers()
  let last = this.state.last
  var next = set.ref.collection("users").startAfter(last).limit(12);
  next.get().then(function (documentSnapshots) {
  // Get the last visible document
  var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
  const list = [];
  documentSnapshots.forEach(function(doc) {
    //im fetching only name and avatar url you can get any data 
    //from your firestore as you like
    const { name, avatar_full_url } = doc.data();
    list.push({ key: doc.id, name, avatar_full_url });
  });
  //set state with updated array of data 
  //also save last fetched data in state
  let updated_list = set.state.list.concat(list);
  set.setState({ list: updated_list, last: lastVisible });
  });
};

06-渲染界面

<InfiniteScroll 
  dataLength={this.state.list.length}
  next={this.fetchMoreData}
  hasMore={true}
  loader={<span className="text-secondary">loading</span>}>
    <Row className="mt-3">
      { this.state.list.map((single, index) => (
      <Col lg={4} key={ index }>
        <div>
          <Image src={ single.avatar_full_url }roundedCircle width="100" />
          <h2>{ single.name }</h2>
        </div>
      </Col>
      ))}
    </Row>  
</InfiniteScroll>

答案 2 :(得分:0)

为此使用startAt()或startAfter()

firestore
 .collection("Users")
 .startAt(0)
 .limit(10)
 .get()

答案 3 :(得分:0)

检查这个例子这可以帮助任何尝试上一页/下一页的人

//initial state
const [list, setList] =  useState([]);
const [page, setPage] =  useState(1);

//loading initial data
useEffect(() => {
    const fetchData = async () => {
        await firebase.firestore().collection('users')
            .orderBy('created', 'desc') //order using firestore timestamp
            .limit(5) //change limit value as your need
            .onSnapshot(function(querySnapshot) { 
                var items = [];
                querySnapshot.forEach(function(doc) {
                    items.push({ key: doc.id, ...doc.data() });
                });
                setList(items);
            })
    };
    fetchData();
}, []);

加载初始数据后使用以下函数触发下一个按钮

//next button function
    const showNext = ({ item }) => {
        if(list.length === 0) {
            //use this to show hide buttons if there is no records
        } else {
            const fetchNextData = async () => {
                await firebase.firestore().collection('users')
                    .orderBy('created', 'desc') //order using firestore timestamp
                    .limit(5) //change limit value as your need
                    .startAfter(item.created) //we pass props item's first created timestamp to do start after you can change as per your wish
                    .onSnapshot(function(querySnapshot) {
                        const items = [];
                        querySnapshot.forEach(function(doc) {
                            items.push({ key: doc.id, ...doc.data() });
                        });
                        setList(items);
                        setPage(page + 1) //in case you like to show current page number you can use this
                    })
            };
            fetchNextData();
        }
    };
    

然后上一个按钮功能

//previous button function
const showPrevious = ({item}) => {
    const fetchPreviousData = async () => {
        await firebase.firestore().collection('users')
            .orderBy('created', 'desc')
            .endBefore(item.created) //this is important when we go back
            .limitToLast(5) //this is important when we go back
            .onSnapshot(function(querySnapshot) {
                const items = [];
                querySnapshot.forEach(function(doc) {
                    items.push({ key: doc.id, ...doc.data() });
                });
                setList(items);
                setPage(page - 1)
            })
    };
    fetchPreviousData();
};

最后创建列表视图和两个这样的按钮

 {
    //list doc's here this will come inside return (place this code inside table)
    list.map((doc) => (
        <tr key={doc.key}>
            <td>{ doc.name }</td>
            <td>{ doc.age }</td>
            <td>{ doc.note }</td>
        </tr>
    ))
}


{
    //show previous button only when we have items
    //pass first item to showPrevious function 
    page === 1 ? '' : 
    <Button onClick={() => showPrevious({ item: list[0] }) }>Previous</Button>
}

{
    //show next button only when we have items
    //pass last item to showNext function 
    list.length < 5 ? '' :
    <Button onClick={() => showNext({ item: list[list.length - 1] })}>Next</Button>
}

就是检查我的代码注释,您可以根据需要进行更改。这就是使用 Firebase FireStore 进行分页时会发生的情况。您可以根据需要使用创建自定义钩子来重用这些组件。

希望这可以帮助某人所以我做了一个要点检查it here