diff --git a/webui/src/components/console/TerminalLine.tsx b/webui/src/components/console/TerminalLine.tsx index 8084a24..e512fcc 100644 --- a/webui/src/components/console/TerminalLine.tsx +++ b/webui/src/components/console/TerminalLine.tsx @@ -1,3 +1,5 @@ +import { memo } from 'react' + import { cn } from '@/lib/utils' import type { LogEntry } from '@/types/crawler' @@ -41,7 +43,18 @@ const levelIcons: Record = { debug: 'DBG', } -export function TerminalLine({ log }: TerminalLineProps) { +/** + * 一行日志。 + * + * **必须 memo。** 日志是「来一条就 push 一条」,每来一条 store 里的数组就是新的, + * 于是整个列表重渲染;而这个列表最多留 500 条 —— 不做 memo 就是每来一行重渲染 500 行, + * 每行还要跑 5 次 `cn()`(tailwind-merge 不便宜)。爬虫在跑的时候日志是成片来的, + * 主线程直接被占满,表现就是**点什么都没反应**(点折叠最容易注意到,因为那一下还要 + * 把整份列表挂载/卸载一遍)。 + * + * `log` 对象在数组里是稳定引用,所以 memo 之后只有新来的那一行会渲染。 + */ +export const TerminalLine = memo(function TerminalLine({ log }: TerminalLineProps) { const config = levelConfig[log.level] || levelConfig.info return ( @@ -67,4 +80,4 @@ export function TerminalLine({ log }: TerminalLineProps) { ) -} +})