From bd8fc6ad7b7258c66a8abcfd5cc58d22f6391d26 Mon Sep 17 00:00:00 2001 From: vitaliy Date: Thu, 12 Jul 2018 01:53:42 +0300 Subject: [PATCH] ht3_2: add lazy loading --- .../events/events-table-virtualized.js | 59 ++++++++++------ admin/src/ducks/events.js | 67 ++++++++++++++++++- 2 files changed, 106 insertions(+), 20 deletions(-) diff --git a/admin/src/components/events/events-table-virtualized.js b/admin/src/components/events/events-table-virtualized.js index 272ce38..0f2ee5e 100644 --- a/admin/src/components/events/events-table-virtualized.js +++ b/admin/src/components/events/events-table-virtualized.js @@ -1,9 +1,10 @@ import React, { Component } from 'react' import { connect } from 'react-redux' -import { Table, Column } from 'react-virtualized' +import { InfiniteLoader, Table, Column } from 'react-virtualized' import { - fetchAllEvents, + fetchLazyEvents, selectEvent, + loadMoreEvents, eventListSelector, loadedSelector, loadingSelector @@ -15,34 +16,54 @@ export class EventsTableVirtualized extends Component { static propTypes = {} componentDidMount() { - this.props.fetchAllEvents() + this.props.fetchLazyEvents() } - render() { + get isFirstLoading() { const { events, loading } = this.props - if (loading) return + return loading && events.length === 0 + } + render() { + const { events } = this.props + if (this.isFirstLoading) return return ( - - - - -
+ {({ onRowsRendered, registerChild }) => ( + + + + +
+ )} + ) } rowGetter = ({ index }) => this.props.events[index] handleSelect = ({ rowData }) => this.props.selectEvent(rowData.uid) + + isRowLoaded = ({ index }) => !!this.props.events[index] + + loadMoreRows = () => { + this.props.fetchLazyEvents() + } } export default connect( @@ -51,5 +72,5 @@ export default connect( loading: loadingSelector(state), loaded: loadedSelector(state) }), - { fetchAllEvents, selectEvent } + { fetchLazyEvents, selectEvent } )(EventsTableVirtualized) diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index 2718eed..b20fe72 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -14,8 +14,15 @@ const prefix = `${appName}/${moduleName}` export const FETCH_ALL_REQUEST = `${prefix}/FETCH_ALL_REQUEST` export const FETCH_ALL_START = `${prefix}/FETCH_ALL_START` export const FETCH_ALL_SUCCESS = `${prefix}/FETCH_ALL_SUCCESS` + +export const FETCH_LAZY_REQUEST = `${prefix}/FETCH_REQUEST` +export const FETCH_LAZY_START = `${prefix}/FETCH_START` +export const FETCH_LAZY_SUCCESS = `${prefix}/FETCH_SUCCESS` + export const TOGGLE_SELECT = `${prefix}/TOGGLE_SELECT` +export const REQUEST_LIMIT = 10 + /** * Reducer * */ @@ -41,6 +48,7 @@ export default function reducer(state = new ReducerRecord(), action) { switch (type) { case FETCH_ALL_START: + case FETCH_LAZY_START: return state.set('loading', true) case FETCH_ALL_SUCCESS: @@ -49,6 +57,15 @@ export default function reducer(state = new ReducerRecord(), action) { .set('loaded', true) .set('entities', fbToEntities(payload, EventRecord)) + case FETCH_LAZY_SUCCESS: + const { loaded, events } = payload + return state + .set('loading', false) + .set('loaded', loaded) + .update('entities', (entities) => + entities.push(...fbToEntities(events, EventRecord)) + ) + case TOGGLE_SELECT: return state.update( 'selected', @@ -111,6 +128,10 @@ export const selectEvent = (uid) => ({ payload: { uid } }) +export const fetchLazyEvents = () => ({ + type: FETCH_LAZY_REQUEST +}) + /** * Sagas * */ @@ -132,6 +153,50 @@ export function* fetchAllSaga() { }) } +export function* fetchLazySaga(action) { + const eventsState = yield select(stateSelector) + if (eventsState.loading || eventsState.loaded) return + + yield put({ + type: FETCH_LAZY_START + }) + + const eventList = yield select(entitiesSelector) + const lastLoadedEvent = eventList.last() + const lastUId = lastLoadedEvent ? lastLoadedEvent.get('uid') : '' + + const ref = firebase + .database() + .ref('events') + .orderByKey() + .limitToFirst(REQUEST_LIMIT) + .startAt(lastUId) + const snapshot = yield call([ref, ref.once], 'value') + + const events = snapshot.val() + + //remove repeated previous last event + const filteredEvents = Object.keys(events) + .filter((key) => key !== lastUId) + .reduce((obj, key) => { + obj[key] = events[key] + return obj + }, {}) + + const loaded = Object.keys(events).length < REQUEST_LIMIT + + yield put({ + type: FETCH_LAZY_SUCCESS, + payload: { + events: filteredEvents, + loaded + } + }) +} + export function* saga() { - yield all([takeEvery(FETCH_ALL_REQUEST, fetchAllSaga)]) + yield all([ + takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), + takeEvery(FETCH_LAZY_REQUEST, fetchLazySaga) + ]) }