Refactor ElipsisText Component for Improved State Management
- Replaced refs with state variables for container and measure elements to enhance reactivity and maintainability. - Updated layout effects to utilize new state variables, ensuring accurate measurement and truncation logic. - Improved cleanup logic in useLayoutEffect to prevent memory leaks and ensure proper event handling for font loading and observers.
This commit is contained in:
parent
cb49baaf93
commit
59f603d05d
@ -31,42 +31,60 @@ const ElipsisText = ({ children, style, className, title, code, ...rest }) => {
|
||||
const text = childrenToString(children)
|
||||
const { start, end } = splitMiddle(text)
|
||||
|
||||
const containerRef = useRef(null)
|
||||
const measureRef = useRef(null)
|
||||
const [containerEl, setContainerEl] = useState(null)
|
||||
const [measureEl, setMeasureEl] = useState(null)
|
||||
const truncatedRef = useRef(false)
|
||||
const [truncated, setTruncated] = useState(false)
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const container = containerRef.current
|
||||
const measure = measureRef.current
|
||||
if (!container || !measure) return
|
||||
if (!containerEl || !measureEl) return
|
||||
|
||||
let raf1 = 0
|
||||
let raf2 = 0
|
||||
let cancelled = false
|
||||
|
||||
const update = () => {
|
||||
const available = container.getBoundingClientRect().width
|
||||
if (cancelled) return
|
||||
|
||||
const available = containerEl.getBoundingClientRect().width
|
||||
if (available < 1) return
|
||||
|
||||
const textWidth = measure.getBoundingClientRect().width
|
||||
const textWidth = measureEl.getBoundingClientRect().width
|
||||
const next = Boolean(end) && textWidth > available
|
||||
if (truncatedRef.current === next) return
|
||||
|
||||
truncatedRef.current = next
|
||||
setTruncated(next)
|
||||
}
|
||||
|
||||
update()
|
||||
const frame = requestAnimationFrame(update)
|
||||
raf1 = requestAnimationFrame(() => {
|
||||
update()
|
||||
raf2 = requestAnimationFrame(update)
|
||||
})
|
||||
|
||||
const resizeObserver = new ResizeObserver(update)
|
||||
resizeObserver.observe(container)
|
||||
resizeObserver.observe(containerEl)
|
||||
|
||||
const intersectionObserver = new IntersectionObserver(update)
|
||||
intersectionObserver.observe(container)
|
||||
intersectionObserver.observe(containerEl)
|
||||
|
||||
const onFontsReady = () => {
|
||||
if (!cancelled) update()
|
||||
}
|
||||
const fonts = typeof document !== 'undefined' ? document.fonts : null
|
||||
fonts?.ready?.then(onFontsReady)
|
||||
fonts?.addEventListener?.('loadingdone', onFontsReady)
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(frame)
|
||||
cancelled = true
|
||||
cancelAnimationFrame(raf1)
|
||||
cancelAnimationFrame(raf2)
|
||||
resizeObserver.disconnect()
|
||||
intersectionObserver.disconnect()
|
||||
fonts?.removeEventListener?.('loadingdone', onFontsReady)
|
||||
}
|
||||
}, [text, end])
|
||||
}, [containerEl, measureEl, text, end])
|
||||
|
||||
const showTruncated = truncated && Boolean(end)
|
||||
const RootTag = code ? 'code' : 'span'
|
||||
@ -74,9 +92,9 @@ const ElipsisText = ({ children, style, className, title, code, ...rest }) => {
|
||||
const content = (
|
||||
<span
|
||||
className={showTruncated ? 'elipsis-text is-truncated' : 'elipsis-text'}
|
||||
ref={containerRef}
|
||||
ref={setContainerEl}
|
||||
>
|
||||
<RootTag className='elipsis-text-measure' ref={measureRef}>
|
||||
<RootTag className='elipsis-text-measure' ref={setMeasureEl}>
|
||||
{text}
|
||||
</RootTag>
|
||||
<RootTag className='elipsis-text-full'>{text}</RootTag>
|
||||
@ -96,7 +114,7 @@ const ElipsisText = ({ children, style, className, title, code, ...rest }) => {
|
||||
className={['elipsis-text-wrapper', className].filter(Boolean).join(' ')}
|
||||
style={style}
|
||||
>
|
||||
{truncated ? <Tooltip title={title ?? text}>{content}</Tooltip> : content}
|
||||
<Tooltip title={truncated ? (title ?? text) : null}>{content}</Tooltip>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user