【问题标题】:Firestore pagination with react-redux使用 react-redux 进行 Firestore 分页
【发布时间】:2021-03-31 15:37:41
【问题描述】:

我尝试使用 firebase 和 react redux-toolkit 添加分页。我明白了逻辑,但在使用 redux 时遇到了问题。

起初我想将 lastDoc 设置为 redux 状态,但由于它是一个对象而出现错误。

然后我改变了方式,开始保持最后一个文档的id状态。但后来我无法获得 firebase doc 本身

const lastDocRef = firestoreDB.doc(`catalog/${publishedBooks.lastDocId}`)

不一样

const lastDoc = snap.docs[snap.docs.length-1];

感谢您对如何解决此问题的任何帮助。

import { createSlice, createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit';
import firebaseService from 'app/services/firebaseService';

const firestoreDB = firebaseService.firestoreDB;

export const getPublishedBooks = createAsyncThunk('adminApp/publishedBooks/getPublishedBooks',
    async (params, { dispatch, getState }) => {
        const promise = firestoreDB
            .collection('catalog')
            .orderBy('lastPublish', 'desc')
            .limit(10)
            .get()
            .then(snap => {
                const lastDoc = snap.docs[snap.docs.length-1];
                dispatch(setLastDocId(lastDoc.id));
                let books = [];
                snap.forEach(bookDoc => {
                    const id = bookDoc.id;
                    const data = bookDoc.data();
                    const lastPublish = data.lastPublish.toDate().toISOString();
                    books.push({ ...data, id, lastPublish });
                });
                return books;
            })
            .catch(error => {
                return {}
            });

        const result = await promise;
        return result;
    }
);

export const getPublishedBooksNext = createAsyncThunk('adminApp/publishedBooks/getPublishedBooksNext',
    async (params, { dispatch, getState }) => {
        const { publishedBooks } = getState().adminApp;

        const lastDocRef = firestoreDB.doc(`catalog/${publishedBooks.lastDocId}`)

        const promise = firestoreDB
            .collection('catalog')
            .orderBy('lastPublish', 'desc')
            .startAfter(lastDocRef)
            .limit(10)
            .get()
            .then(snap => {
                const lastDoc = snap.docs[snap.docs.length-1];
                dispatch(setLastDocId(lastDoc.id));
                let books = [];
                snap.forEach(bookDoc => {
                    const id = bookDoc.id;
                    const data = bookDoc.data();
                    const lastPublish = data.lastPublish.toDate().toISOString();
                    books.push({ ...data, id, lastPublish });
                });
                return books;
            })
            .catch(error => {
                return {}
            });

        const result = await promise;
        return result;
    }
);

const publishedBooksAdapter = createEntityAdapter({});
const initialState = publishedBooksAdapter.getInitialState({
    lastDocId: null
});

export const {
    selectAll: selectPublishedBooks,
    selectById: selectPublishedBookById,
    selectTotal: selectPublishedBooksTotal
} = publishedBooksAdapter.getSelectors(state => state.adminApp.publishedBooks);

const publishedBooksSlice = createSlice({
    name: 'adminApp/publishedBooks',
    initialState,
    reducers: {
        resetPublishedBooks: (state, action) => initialState,
        setLastDocId: {
            prepare: doc => {
                const payload = doc
                return { payload };
            },
            reducer: (state, action) => {
                state.lastDocId = action.payload;
            }
        },
        resetLastDocId: {
            prepare: () => {
                const payload = null
                return { payload };
            },
            reducer: (state, action) => {
                state.lastDocId = action.payload;
            }
        },
    },
    extraReducers: {
        [getPublishedBooks.fulfilled]: publishedBooksAdapter.setAll,
        [getPublishedBooksNext.fulfilled]: publishedBooksAdapter.upsertMany
    }
});

export const { resetPublishedBooks, setLastDocId, resetLastDocId } = publishedBooksSlice.actions;

export default publishedBooksSlice.reducer;

【问题讨论】:

  • lastDoc 不起作用?

标签: javascript reactjs firebase google-cloud-firestore react-redux


【解决方案1】:

lastDocRef 只返回文档引用。您需要获取实际的文档本身。

const lastDocRef = await firestoreDB.doc(`catalog/${publishedBooks.lastDocId}`).get();

您应该使用await 而不是then-catch 以获得更易读的代码。

export const getPublishedBooksNext = createAsyncThunk('adminApp/publishedBooks/getPublishedBooksNext',
    async (params, { dispatch, getState }) => {
        const { publishedBooks } = getState().adminApp;

        try {
            const lastDocRef = await firestoreDB.doc(`catalog/${publishedBooks.lastDocId}`).get();

            const snap = await firestoreDB
                .collection('catalog')
                .orderBy('lastPublish', 'desc')
                .startAfter(lastDocRef)
                .limit(10)
                .get()
            
            const lastDoc = snap.docs[snap.docs.length-1];
            let books = [];
            dispatch(setLastDocId(lastDoc.id));
            snap.forEach(bookDoc => {
                const id = bookDoc.id;
                const data = bookDoc.data();
                const lastPublish = data.lastPublish.toDate().toISOString();
                books.push({ ...data, id, lastPublish });
            });

            return books;
        } catch (error) {
            return {}
        }
    }
);

编辑:您还可以将 lastDoc 保存到 redux,然后稍后引用它以避免为 lastDocRef 提取额外的工作负载。

export const getPublishedBooksNext = createAsyncThunk('adminApp/publishedBooks/getPublishedBooksNext',
    async (params, { dispatch, getState }) => {
        const { lastDocRef } = getState().adminApp; // get saved lastDoc 
    
        try {
            const snap = await firestoreDB
                .collection('catalog')
                .orderBy('lastPublish', 'desc')
                .startAfter(lastDocRef) // use it here. 
                .limit(10)
                .get()
            
            const lastDoc = snap.docs[snap.docs.length-1];
            let books = [];
            // dispatch(setLastDocId(lastDoc.id)); // instead of saving the doc id 
            dispatch(setLastDoc(lastDoc)); // save the last document instead 
            
            snap.forEach(bookDoc => {
                const id = bookDoc.id;
                const data = bookDoc.data();
                const lastPublish = data.lastPublish.toDate().toISOString();
                books.push({ ...data, id, lastPublish });
            });

            return books;
        } catch (error) {
            return {}
        }
    }
);

【讨论】:

  • 当我使用实际的文档本身时,它可以工作。谢谢。但是第二个解决方案返回错误:“在状态中检测到不可序列化的值,在路径中:`adminApp.lastDoc” 保存文档本身也是我的第一个选择
猜你喜欢
  • 2019-02-05
  • 1970-01-01
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
  • 2019-02-11
相关资源
最近更新 更多