From b0a03059bc936951056b960ec94dbc28461ce9ed Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 27 May 2018 15:53:25 +0000 Subject: [PATCH 1/2] add tests for events-table-virtualized --- .../events/events-table-virtualized.test.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 admin/src/components/events/events-table-virtualized.test.js diff --git a/admin/src/components/events/events-table-virtualized.test.js b/admin/src/components/events/events-table-virtualized.test.js new file mode 100644 index 0000000..7040ff5 --- /dev/null +++ b/admin/src/components/events/events-table-virtualized.test.js @@ -0,0 +1,21 @@ +import React from 'react' +import { EventsTable } from './events-table-virtualized' +import { shallow, mount } from 'enzyme' +import eventsMocks from '../../mocks/conferences' + +const events = eventsMocks.map((event) => ({ + ...event, + uid: Math.random().toString() +})) + +describe('EventsTable', () => { + it('should render some events', () => { + const container = mount() + + expect(container.find('.test--event-list_item').length).toBeGreaterThan(1) + }) + + it('should fetch events', (done) => { + shallow( done()} />) + }) +}) From 61d216cf86dedc8d1e991828056c3531831f7460 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 27 May 2018 16:31:10 +0000 Subject: [PATCH 2/2] add lazy-loading to events --- .../events/events-table-virtualized.js | 51 +++++++++++------ admin/src/ducks/events.js | 55 ++++++++++++++++++- 2 files changed, 86 insertions(+), 20 deletions(-) diff --git a/admin/src/components/events/events-table-virtualized.js b/admin/src/components/events/events-table-virtualized.js index eb5ba6c..92f5866 100644 --- a/admin/src/components/events/events-table-virtualized.js +++ b/admin/src/components/events/events-table-virtualized.js @@ -1,42 +1,57 @@ import React, { Component } from 'react' import { connect } from 'react-redux' import { - fetchAllEvents, + fetchLazyEvents, toggleSelection as handleSelect, eventListSelector, loadedSelector, loadingSelector } from '../../ducks/events' -import Loader from '../common/loader' -import { Table, Column } from 'react-virtualized' +import { InfiniteLoader, Table, Column } from 'react-virtualized' import 'react-virtualized/styles.css' export class EventsTable extends Component { static propTypes = {} componentDidMount() { - this.props.fetchAllEvents && this.props.fetchAllEvents() + this.fetchEvents() } render() { - const { loading, events } = this.props - if (loading) return + const { events, loaded } = this.props return ( - - - - -
+ {({ onRowsRendered, registerChild }) => ( + + + + +
+ )} + ) } + fetchEvents = () => { + this.props.fetchLazyEvents && this.props.fetchLazyEvents() + } + + isRowLoaded = () => this.props.loaded + rowGetter = ({ index }) => this.props.events[index] } @@ -46,5 +61,5 @@ export default connect( loading: loadingSelector(state), loaded: loadedSelector(state) }), - { fetchAllEvents, handleSelect } + { fetchLazyEvents, handleSelect } )(EventsTable) diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index 74107b8..d0230c3 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -1,4 +1,4 @@ -import { all, takeEvery, put, call } from 'redux-saga/effects' +import { all, takeEvery, put, call, take, select } from 'redux-saga/effects' import { appName } from '../config' import { Record, OrderedSet, OrderedMap } from 'immutable' import firebase from 'firebase/app' @@ -14,6 +14,9 @@ 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_LAZY_REQUEST` +export const FETCH_LAZY_START = `${prefix}/FETCH_LAZY_START` +export const FETCH_LAZY_SUCCESS = `${prefix}/FETCH_LAZY_SUCCESS` export const TOGGLE_SELECTION = `${prefix}/TOGGLE_SELECTION` /** @@ -41,6 +44,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 +53,12 @@ export default function reducer(state = new ReducerRecord(), action) { .set('loaded', true) .set('entities', fbToEntities(payload, EventRecord)) + case FETCH_LAZY_SUCCESS: + return state + .set('loading', false) + .set('loaded', Object.keys(payload).length < 10) + .mergeIn(['entities'], fbToEntities(payload, EventRecord)) + case TOGGLE_SELECTION: return state.update( 'selected', @@ -83,6 +93,9 @@ export const loadedSelector = createSelector( export const eventListSelector = createSelector(entitiesSelector, (entities) => entities.valueSeq().toArray() ) +export const lastEventSelector = createSelector(entitiesSelector, (entities) => + entities.last() +) export const selectedIdsSelector = createSelector(stateSelector, (state) => state.selected.toArray() @@ -104,6 +117,12 @@ export function fetchAllEvents() { } } +export function fetchLazyEvents() { + return { + type: FETCH_LAZY_REQUEST + } +} + export function toggleSelection(uid) { return { type: TOGGLE_SELECTION, @@ -130,6 +149,38 @@ export function* fetchAllSaga() { }) } +export function* fetchLazySaga() { + while (true) { + yield take(FETCH_LAZY_REQUEST) + + const loaded = yield select(loadedSelector) + if (loaded) return + + const loading = yield select(loadingSelector) + if (loading) continue + + yield put({ + type: FETCH_LAZY_START + }) + + const lastEvent = yield select(lastEventSelector) + + const ref = firebase + .database() + .ref('events') + .orderByKey() + .limitToFirst(10) + .startAt(lastEvent ? lastEvent.uid : '') + + const snapshot = yield call([ref, ref.once], 'value') + + yield put({ + type: FETCH_LAZY_SUCCESS, + payload: snapshot.val() + }) + } +} + export function* saga() { - yield all([takeEvery(FETCH_ALL_REQUEST, fetchAllSaga)]) + yield all([takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), fetchLazySaga()]) }