From d9f39a8d673f3ecc197591b8c7f209ea45412f45 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Thu, 7 Nov 2019 18:15:38 +0700 Subject: [PATCH] optimizedbig amount of data rendering --- src/components/flow/Cell/index.tsx | 116 +++++++++++++++++---------- src/components/flow/Cell/styles.scss | 10 +++ src/redux/flow/sagas.ts | 16 ++-- 3 files changed, 92 insertions(+), 50 deletions(-) diff --git a/src/components/flow/Cell/index.tsx b/src/components/flow/Cell/index.tsx index c0ae09b6..d4e3d85e 100644 --- a/src/components/flow/Cell/index.tsx +++ b/src/components/flow/Cell/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState, useCallback, useEffect } from 'react'; +import React, { FC, useState, useCallback, useEffect, useRef } from 'react'; import { INode } from '~/redux/types'; import { getURL, formatCellText } from '~/utils/dom'; import classNames from 'classnames'; @@ -7,6 +7,7 @@ import * as styles from './styles.scss'; import { Icon } from '~/components/input/Icon'; import { flowSetCellView } from '~/redux/flow/actions'; import { PRESETS } from '~/constants/urls'; +import { debounce } from 'throttle-debounce'; interface IProps { node: INode; @@ -23,7 +24,33 @@ const Cell: FC = ({ onSelect, onChangeCellView, }) => { + const ref = useRef(null); const [is_loaded, setIsLoaded] = useState(false); + const [is_visible, setIsVisible] = useState(false); + + const checkIfVisible = useCallback(() => { + if (!ref.current) return; + + const { top, height } = ref.current.getBoundingClientRect(); + + const visibility = top + height > -window.innerHeight && top < window.innerHeight * 2; + + if (visibility !== is_visible) setIsVisible(visibility); + }, [ref, is_visible, setIsVisible]); + + const checkIfVisibleDebounced = useCallback(debounce(200 + Math.random() * 200, checkIfVisible), [ + checkIfVisible, + ]); + + useEffect(() => { + checkIfVisible(); + }, []); + + useEffect(() => { + window.addEventListener('scroll', checkIfVisibleDebounced); + + return () => window.removeEventListener('scroll', checkIfVisibleDebounced); + }, [checkIfVisibleDebounced]); const onImageLoad = useCallback(() => { setIsLoaded(true); @@ -67,51 +94,56 @@ const Cell: FC = ({ className={classNames(styles.cell, styles[(flow && flow.display) || 'single'], { [styles.is_text]: false, })} + ref={ref} > - {can_edit && ( -
-
- -
+ {is_visible && ( + <> + {can_edit && ( +
+
+ +
-
- {has_description && ( - <> - -
- - )} - - - - -
-
- )} - -
-
- {title &&
{title}
} - {text && ( -
+
+ {has_description && ( + <> + +
+ + )} + + + + +
+
)} -
-
- {thumbnail && ( -
- -
+
+
+ {title &&
{title}
} + {text && ( +
+ )} +
+
+ + {thumbnail && ( +
+ +
+ )} + )}
); diff --git a/src/components/flow/Cell/styles.scss b/src/components/flow/Cell/styles.scss index 311728ab..7f488216 100644 --- a/src/components/flow/Cell/styles.scss +++ b/src/components/flow/Cell/styles.scss @@ -124,6 +124,15 @@ } } +@keyframes appear { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + .face { @include outer_shadow(); @@ -141,6 +150,7 @@ padding: $gap; pointer-events: none; touch-action: none; + animation: appear 1s forwards; @media (min-width: $cell * 2 + $grid_line) { .vertical > &.has_text, diff --git a/src/redux/flow/sagas.ts b/src/redux/flow/sagas.ts index 527353d4..dfd738ce 100644 --- a/src/redux/flow/sagas.ts +++ b/src/redux/flow/sagas.ts @@ -17,7 +17,7 @@ import { IFlowState } from './reducer'; function* onGetFlow() { const { - data: { nodes = null, heroes = null, recent = [], updated = [] }, + data: { nodes = [], heroes = [], recent = [], updated = [] }, }: IResultWithStatus<{ nodes: IFlowState['nodes']; heroes: IFlowState['heroes']; @@ -25,13 +25,13 @@ function* onGetFlow() { updated: IFlowState['updated']; }> = yield call(reqWrapper, getNodes, {}); - if (!nodes || !nodes.length) { - yield put(flowSetNodes([])); - yield put(flowSetHeroes([])); - yield put(flowSetRecent([])); - yield put(flowSetUpdated([])); - return; - } + // if (!nodes || !nodes.length) { + // yield put(flowSetNodes([])); + // yield put(flowSetHeroes([])); + // yield put(flowSetRecent([])); + // yield put(flowSetUpdated([])); + // return; + // } yield put(flowSetNodes(nodes)); yield put(flowSetHeroes(heroes));