refactor(frontend):create useLatestRef & useCancelableTimeout hooks; incapsulate autoscroll logic in useAutoscroll hook (so far ConsolePanel only)
This commit is contained in:
parent
76b78150ef
commit
ca7a93feb9
4 changed files with 88 additions and 41 deletions
|
|
@ -4,6 +4,7 @@ import BottomBlock from '../BottomBlock';
|
|||
import { Tabs, Input, Icon, NoContent } from 'UI';
|
||||
import cn from 'classnames';
|
||||
import ConsoleRow from '../ConsoleRow';
|
||||
import useLatestRef from 'App/hooks/useLatestRef'
|
||||
import { getRE } from 'App/utils';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
|
@ -11,6 +12,7 @@ import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtuali
|
|||
import { useStore } from 'App/mstore';
|
||||
import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import useAutoscroll from '../useAutoscroll';
|
||||
|
||||
const ALL = 'ALL';
|
||||
const INFO = 'INFO';
|
||||
|
|
@ -57,7 +59,6 @@ const getIconProps = (level: any) => {
|
|||
|
||||
|
||||
const INDEX_KEY = 'console';
|
||||
const TIMEOUT_DURATION = 5000;
|
||||
|
||||
function ConsolePanel() {
|
||||
const {
|
||||
|
|
@ -70,7 +71,6 @@ function ConsolePanel() {
|
|||
const activeIndex = devTools[INDEX_KEY].index;
|
||||
const [isDetailsModalActive, setIsDetailsModalActive] = useState(false);
|
||||
const [filteredList, setFilteredList] = useState([]);
|
||||
const [autoScroll, setAutoScroll] = useState(activeIndex === 0);
|
||||
const { showModal } = useModal();
|
||||
const [logs, setLogs] = useState([])
|
||||
|
||||
|
|
@ -95,48 +95,24 @@ function ConsolePanel() {
|
|||
const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab })
|
||||
const onFilterChange = ({ target: { value } }: any) => devTools.update(INDEX_KEY, { filter: value })
|
||||
|
||||
|
||||
const autoScrollIndex = logListNow.length + exceptionsListNow.length
|
||||
// AutoScroll index update
|
||||
useEffect(() => {
|
||||
if (autoScroll && autoScrollIndex !== activeIndex) {
|
||||
devTools.update(INDEX_KEY, { index: autoScrollIndex }) // can just scroll here
|
||||
}
|
||||
}, [autoScroll, autoScrollIndex])
|
||||
|
||||
const timeoutIDRef = React.useRef<ReturnType<typeof setTimeout>>()
|
||||
const timeoutStartAutoScroll = () => {
|
||||
clearTimeout(timeoutIDRef.current);
|
||||
timeoutIDRef.current = setTimeout(() => {
|
||||
setAutoScroll(true)
|
||||
}, TIMEOUT_DURATION);
|
||||
}
|
||||
const stopAutoScroll = () => {
|
||||
clearTimeout(timeoutIDRef.current)
|
||||
setAutoScroll(false)
|
||||
}
|
||||
const onMouseEnter = stopAutoScroll
|
||||
// AutoScroll
|
||||
const autoScrollIndex = logListNow.length + exceptionsListNow.length
|
||||
const {
|
||||
timeoutStartAutoscroll,
|
||||
stopAutoscroll,
|
||||
} = useAutoscroll(
|
||||
activeIndex,
|
||||
autoScrollIndex,
|
||||
index => devTools.update(INDEX_KEY, { index })
|
||||
)
|
||||
|
||||
const onMouseEnter = stopAutoscroll
|
||||
const onMouseLeave = () => {
|
||||
if (isDetailsModalActive) { return }
|
||||
timeoutStartAutoScroll()
|
||||
timeoutStartAutoscroll()
|
||||
}
|
||||
|
||||
// latest ref
|
||||
const autoScrollRef = useRef(autoScroll)
|
||||
useEffect(() => { autoScrollRef.current = autoScroll }, [ autoScroll ])
|
||||
useEffect(() => {
|
||||
if (!autoScroll) {
|
||||
timeoutStartAutoScroll()
|
||||
}
|
||||
return () => {
|
||||
clearTimeout(timeoutIDRef.current)
|
||||
if (autoScrollRef.current) {
|
||||
devTools.update(INDEX_KEY, { index: 0 }) // index:0 means autoscroll is active
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
const cache = new CellMeasurerCache({
|
||||
fixedWidth: true,
|
||||
keyMapper: (index: number) => filteredList[index],
|
||||
|
|
@ -158,11 +134,11 @@ function ConsolePanel() {
|
|||
right: true,
|
||||
onClose: () => {
|
||||
setIsDetailsModalActive(false)
|
||||
timeoutStartAutoScroll()
|
||||
timeoutStartAutoscroll()
|
||||
}
|
||||
});
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(log) });
|
||||
stopAutoScroll()
|
||||
stopAutoscroll()
|
||||
}
|
||||
const _rowRenderer = ({ index, key, parent, style }: any) => {
|
||||
const item = filteredList[index];
|
||||
|
|
|
|||
43
frontend/app/components/shared/DevTools/useAutoscroll.ts
Normal file
43
frontend/app/components/shared/DevTools/useAutoscroll.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { useEffect, useState, useRef } from 'react'
|
||||
import useLatestRef from 'App/hooks/useLatestRef'
|
||||
import useCancelableTimeout from 'App/hooks/useCancelableTimeout'
|
||||
|
||||
const TIMEOUT_DURATION = 5000;
|
||||
|
||||
export default function useAutoscroll(
|
||||
savedIndex: number,
|
||||
autoscrollIndex: number,
|
||||
updadteIndex: (index: number) => void,
|
||||
) {
|
||||
const [ autoscroll, setAutoscroll ] = useState(savedIndex === 0)
|
||||
|
||||
const [ timeoutStartAutoscroll, stopAutoscroll ] = useCancelableTimeout(
|
||||
() => setAutoscroll(true),
|
||||
() => setAutoscroll(false),
|
||||
TIMEOUT_DURATION,
|
||||
)
|
||||
useEffect(() => {
|
||||
if (autoscroll && autoscrollIndex !== savedIndex) {
|
||||
updadteIndex(autoscrollIndex)
|
||||
}
|
||||
}, [ autoscroll, autoscrollIndex ])
|
||||
|
||||
const autoScrollRef = useLatestRef(autoscroll)
|
||||
useEffect(() => {
|
||||
if (!autoscroll) {
|
||||
timeoutStartAutoscroll()
|
||||
}
|
||||
return () => {
|
||||
if (autoScrollRef.current) {
|
||||
updadteIndex(0) // index:0 means autoscroll is active
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return {
|
||||
autoscrollIndex,
|
||||
timeoutStartAutoscroll,
|
||||
stopAutoscroll,
|
||||
}
|
||||
|
||||
}
|
||||
20
frontend/app/hooks/useCancelableTimeout.ts
Normal file
20
frontend/app/hooks/useCancelableTimeout.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { useRef, useEffect } from 'react'
|
||||
|
||||
|
||||
export default function useCancelableTimeout(
|
||||
onTimeout: ()=> void,
|
||||
onCancel: ()=> void,
|
||||
delay: number,
|
||||
): [()=> void, ()=> void] {
|
||||
const idRef = useRef<ReturnType<typeof setTimeout>>()
|
||||
const triggerTimeout = () => {
|
||||
clearTimeout(idRef.current)
|
||||
idRef.current = setTimeout(onTimeout, delay)
|
||||
}
|
||||
const cancelTimeout = () => {
|
||||
clearTimeout(idRef.current)
|
||||
onCancel()
|
||||
}
|
||||
useEffect(() => () => clearTimeout(idRef.current)) // auto-cancel without callback (clean)
|
||||
return [ triggerTimeout, cancelTimeout ]
|
||||
}
|
||||
8
frontend/app/hooks/useLatestRef.ts
Normal file
8
frontend/app/hooks/useLatestRef.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { useRef, useEffect } from 'react'
|
||||
|
||||
|
||||
export default function useLatestRef<T>(state: T) {
|
||||
const ref = useRef<T>(state)
|
||||
useEffect(() => { ref.current = state }, [ state ])
|
||||
return ref
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue