prescottprue / react-redux-firebase

Redux bindings for Firebase. Includes React Hooks and Higher Order Components.
https://react-redux-firebase.com
MIT License
2.55k stars 556 forks source link

question(query): how to implement pagination with firestoreConnect #674

Open selimyalinkilic opened 5 years ago

selimyalinkilic commented 5 years ago

Hi,

I wanna make pagination, but i can't make it. Maybe someone knows how to make it. Can you help me please. My dashboard component codes are as below.

import React, { Component } from 'react';
import ProductListTable from '../products/ProductListTable';
import { connect } from 'react-redux';
import { firestoreConnect } from 'react-redux-firebase';
import { compose } from 'redux';
import { Link, Redirect } from 'react-router-dom';

class Dashboard extends Component {
  render() {
    const { products, auth } = this.props;
    if(!auth.uid) return <Redirect to='/admin/login' />
      return (
        <div className="admin-dashboard">
          <div className="container">
            <h3 className="mt-5 mb-5 text-dark text-center">Product List</h3>
            <div className="row">
              <div className="col-12 mb-2">
                <button className="btn btn-primary btn-sm mr-2" disabled>Delete All</button>
                <Link to="/admin/product/create" className="btn btn-primary btn-sm">Add Product</Link>
              </div>
            </div>
            <ProductListTable products={products} />
          </div>
        </div>
      )
  }
}

const mapStateToProps = (state) ={
  return {
    products: state.firestore.ordered.products,
    auth: state.firebase.auth,
  }
}

export default compose(
  firestoreConnect([
    { 
      collection: 'products',
      orderBy : ['createdAt','desc']
    }
  ]),connect(mapStateToProps)
)(Dashboard);
tsubramanian commented 5 years ago

Have you got to make it work?. Can you shed some lights on how you have solved it? I don't see any reference documentation using the firestoreConnect way.

selimyalinkilic commented 5 years ago

I couldn't find any way. So i didn't make pagination

rajivos commented 4 years ago

Still no one here? I still need help paginating my data using fireStoreConnect

OlesyaKlochko commented 4 years ago

I have the same issue.. Have you found some solution?

dhamilton19 commented 4 years ago

Hi, I was able to get pagination working in a hook by using a hack. I'll post it below. Each paginated batch of records has to be stored with a new key in the ordered object within firestore. This is then able to be merged together when a component requests it. By fetching n+1 records I am able to use the last record to determine if there is a next page.

import {
  useFirestoreConnect,
  useFirebase,
  isEmpty,
  isLoaded,
} from 'react-redux-firebase';
import { useSelector } from 'react-redux';

const mergeLists = (ordered, storeAs, limit) => {
  let nextPage = false;
  let list = Object.entries(ordered).filter(([key, value]) => {
    return key.includes(storeAs);
  });
  list = list.map((item, index) => {
    if (item[1].length - 1 === limit) {
      if (list.length - 1 === index) {
        nextPage = true;
      }
      return item[1].slice(0, -1);
    }
    return item[1];
  });
  return [list.flat(), nextPage];
};

const useHook = ({
  limit,
  startAfter, //uses orderBy timestamp
}) => {
  const storeAs = 'some_key',
  const key = `${storeAs}/${startAfter || 0}`;
  const firebase = useFirebase();

  useFirestoreConnect({
    collection: 'users',
    doc: ...,
    subcollections: ...,
    orderBy: [['timestamp', 'desc']],
    storeAs: key,
    limit: limit + 1,
    startAfter,
  });

  return useSelector(({ firestore: { status, ordered, errors } }) => {
    const loading =
      status.requesting[key] === undefined ||
      Object.entries(status.requesting).some(
        ([key, value]) => key.includes(storeAs) && value,
      );
    const error = Object.entries(errors).find(
      ([key, value]) => key.includes(storeAs) && !!value,
    );
    const [list, nextPage] = mergeLists(ordered, storeAs, limit);
    return {
      loading,
      error,
      data: list,
      nextPage,
    };
  });
};

Within a component:

  const [cursor, setCursor] = useState(undefined);
  const state = useHook({
    startAfter: cursor,
    limit: 20,
  });

Later on a button click:

  setCursor(state.data[state.data.length - 1].timestamp);

Hope this helps

reo-yamashita commented 3 years ago

hi how about back (prev) button ?? anyone who knows how to write with react redux firestore ?