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 text = childrenToString(children)
|
||||||
const { start, end } = splitMiddle(text)
|
const { start, end } = splitMiddle(text)
|
||||||
|
|
||||||
const containerRef = useRef(null)
|
const [containerEl, setContainerEl] = useState(null)
|
||||||
const measureRef = useRef(null)
|
const [measureEl, setMeasureEl] = useState(null)
|
||||||
const truncatedRef = useRef(false)
|
const truncatedRef = useRef(false)
|
||||||
const [truncated, setTruncated] = useState(false)
|
const [truncated, setTruncated] = useState(false)
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const container = containerRef.current
|
if (!containerEl || !measureEl) return
|
||||||
const measure = measureRef.current
|
|
||||||
if (!container || !measure) return
|
let raf1 = 0
|
||||||
|
let raf2 = 0
|
||||||
|
let cancelled = false
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
const available = container.getBoundingClientRect().width
|
if (cancelled) return
|
||||||
|
|
||||||
|
const available = containerEl.getBoundingClientRect().width
|
||||||
if (available < 1) return
|
if (available < 1) return
|
||||||
|
|
||||||
const textWidth = measure.getBoundingClientRect().width
|
const textWidth = measureEl.getBoundingClientRect().width
|
||||||
const next = Boolean(end) && textWidth > available
|
const next = Boolean(end) && textWidth > available
|
||||||
if (truncatedRef.current === next) return
|
if (truncatedRef.current === next) return
|
||||||
|
|
||||||
truncatedRef.current = next
|
truncatedRef.current = next
|
||||||
setTruncated(next)
|
setTruncated(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
update()
|
update()
|
||||||
const frame = requestAnimationFrame(update)
|
raf1 = requestAnimationFrame(() => {
|
||||||
|
update()
|
||||||
|
raf2 = requestAnimationFrame(update)
|
||||||
|
})
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(update)
|
const resizeObserver = new ResizeObserver(update)
|
||||||
resizeObserver.observe(container)
|
resizeObserver.observe(containerEl)
|
||||||
|
|
||||||
const intersectionObserver = new IntersectionObserver(update)
|
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 () => {
|
return () => {
|
||||||
cancelAnimationFrame(frame)
|
cancelled = true
|
||||||
|
cancelAnimationFrame(raf1)
|
||||||
|
cancelAnimationFrame(raf2)
|
||||||
resizeObserver.disconnect()
|
resizeObserver.disconnect()
|
||||||
intersectionObserver.disconnect()
|
intersectionObserver.disconnect()
|
||||||
|
fonts?.removeEventListener?.('loadingdone', onFontsReady)
|
||||||
}
|
}
|
||||||
}, [text, end])
|
}, [containerEl, measureEl, text, end])
|
||||||
|
|
||||||
const showTruncated = truncated && Boolean(end)
|
const showTruncated = truncated && Boolean(end)
|
||||||
const RootTag = code ? 'code' : 'span'
|
const RootTag = code ? 'code' : 'span'
|
||||||
@ -74,9 +92,9 @@ const ElipsisText = ({ children, style, className, title, code, ...rest }) => {
|
|||||||
const content = (
|
const content = (
|
||||||
<span
|
<span
|
||||||
className={showTruncated ? 'elipsis-text is-truncated' : 'elipsis-text'}
|
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}
|
{text}
|
||||||
</RootTag>
|
</RootTag>
|
||||||
<RootTag className='elipsis-text-full'>{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(' ')}
|
className={['elipsis-text-wrapper', className].filter(Boolean).join(' ')}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
{truncated ? <Tooltip title={title ?? text}>{content}</Tooltip> : content}
|
<Tooltip title={truncated ? (title ?? text) : null}>{content}</Tooltip>
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user