react
import { memo, useEffect, useReducer, useRef, useMemo } from 'react'
import cloneDeep from 'lodash/cloneDeep'
import { HugeLogWrapper, HeaderEmptyWrapper, FooterEmptyWrapper } from './styles'
const [currentLog, deepLengthMap, maxLength, splitLength, headerMap, footerMap]: any = [[], new Map(), 10, 2, new Map(), new Map()]
let [data, offset, deep, timeOut, isInit, isUp, isDown, maxDeep]: any = [{ length: maxLength }, 0, 0, void 0, true, false, true, 0]
const initialState = {
contentCount: 0,
}
const reducer = (state: any, payload: any) => ({ ...state, ...payload })
const RenderHugeLog = (props: any) => {
const {
ApiMethod,
logPath,
isRefresh,
} = props
const [state, dispatch] = useReducer(reducer, initialState)
const { contentCount } = state
const domRef: any = useRef(null)
const getContentList = async () => {
do {
const res: any = await ApiMethod({
limit: 10,
logPath,
offset,
})
data = res?.data?.data
const dataLength = data?.length
deepLengthMap.set(deep, { dataLength, offset })
offset += dataLength
currentLog.push({ deep, data })
currentLog?.sort?.((a: any, b: any) => a.deep - b.deep)
if (currentLog.length > maxLength) currentLog.shift()
if (dataLength < 10 || (currentLog.length === maxLength)) {
dispatch({
contentCount: contentCount + 1,
})
isInit = false
}
if (dataLength < 10) maxDeep = deep
deep += 1
} while (data?.length > 9 && currentLog.length < maxLength)
}
const intersectionObserver = new IntersectionObserver((entries: any) => {
if (isInit) return
entries?.forEach?.((entry: any) => {
if (entry?.isIntersecting) {
const entryClassName = entry.target.className
if (entryClassName === 'header_dom' && isUp) {
const firstDeep = currentLog?.[0]?.deep
if (firstDeep >= splitLength) {
currentLog.splice(maxLength - splitLength)
[deep, offset] = [firstDeep - splitLength, deepLengthMap.get(firstDeep - splitLength)?.offset ?? 0]
} else {
[deep, offset] = [0, 0]
}
[isInit, isDown] = [true, true]
getContentList()
if (deep === 0) isUp = false
} else if (entryClassName === 'footer_dom' && isDown) {
const lastDeep = currentLog?.at?.(-1)?.deep
const lastItem = deepLengthMap.get(lastDeep)
[deep, offset] = [lastDeep + 1, lastItem.offset + lastItem.dataLength]
if (maxDeep !== 0 && maxDeep < deep) return
const replaceList = currentLog.splice(0, splitLength)
const headerDom: any = document.querySelector('div.header_dom ')
headerMap.set(Math.floor(replaceList[0]?.deep / splitLength), headerDom?.clientHeight ?? 0)
[isInit, isUp] = [true, true]
getContentList()
}
}
})
})
useEffect(() => {
getContentList()
return () => {
if (timeOut) {
clearTimeout(timeOut)
timeOut = void 0
}
deepLengthMap?.clear?.()
headerMap?.clear?.()
footerMap?.clear?.()
currentLog.length = 0
[data, offset, deep, isInit, isUp, isDown] = [{ length: maxLength }, 0, 0, true, false, true]
}
}, [logPath, isRefresh])
const renderRowDom = (list: any, startRow: number) => (
<>
{
list.map((content: string, index: number) => (
<section className="content_row" key={`${content.slice(0, maxLength)}${index}`}>
<span className="row_number">{startRow + index + 1}</span>
<span className="content_wrapper" dangerouslySetInnerHTML={{ __html: content }} />
</section>
))
}
</>
)
const startRow = deepLengthMap.get(currentLog?.[0]?.deep)?.offset ?? 0
const renderListDom = useMemo(() => {
if (currentLog?.length === maxLength) {
const cloneLogs = cloneDeep(currentLog)
const endLogs = cloneLogs.splice(maxLength - splitLength, splitLength)
const headerLogs = cloneLogs.splice(0, splitLength)
['header_dom', 'footer_dom'].forEach((name: string) => {
const dom = document.querySelector(`div.${name}`)
if (dom) intersectionObserver.unobserve?.(dom)
})
timeOut = setTimeout(() => {
['header_dom', 'footer_dom'].forEach((name: string) => {
const dom = document.querySelector(`div.${name}`)
if (dom) intersectionObserver.observe(dom)
})
})
const headerList = headerLogs?.map?.((item: any) => item.data)?.flat?.() ?? []
const cloneList = cloneLogs?.map?.((item: any) => item.data)?.flat?.() ?? []
const endList = endLogs?.map?.((item: any) => item.data)?.flat?.() ?? []
return (
<>
{
[
{ list: headerList, className: 'header_dom', startRow },
{ list: cloneList, className: 'body_dom', startRow: startRow + headerList.length },
{ list: endList, className: 'footer_dom', startRow: startRow + headerList.length + cloneList.length },
].map(({ list, className, startRow: sr }: any) => (
<div className={className} key={className + startRow}>
{
renderRowDom(list, sr)
}
</div>
))
}
</>
)
}
return renderRowDom(currentLog?.map?.((item: any) => item.data)?.flat?.(), startRow)
}, [contentCount])
let HeaderEmptyHeight = 0
for (let i = 0
HeaderEmptyHeight += headerMap.get(i)
}
return (
<HugeLogWrapper
ref={domRef}
lineWidth={`${startRow + (currentLog?.map?.((item: any) => item.data)?.flat?.()?.length ?? 0)}`.length * 14 + 5}
>
<HeaderEmptyWrapper height={HeaderEmptyHeight} />
{
renderListDom
}
<FooterEmptyWrapper />
</HugeLogWrapper>
)
}
export default memo(RenderHugeLog)