mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 11:44:28 +08:00
refactor: improve MarkdownSvgRenderer re-render
This commit is contained in:
parent
3d44f2da44
commit
5d4a1f49d6
@ -1,5 +1,5 @@
|
||||
import { makeSvgSizeAdaptive } from '@renderer/utils/image'
|
||||
import React, { FC, useEffect, useRef, useState } from 'react'
|
||||
import React, { FC, useEffect, useRef } from 'react'
|
||||
|
||||
interface SvgProps extends React.SVGProps<SVGSVGElement> {
|
||||
'data-needs-measurement'?: 'true'
|
||||
@ -11,35 +11,40 @@ interface SvgProps extends React.SVGProps<SVGSVGElement> {
|
||||
* This component handles two types of SVGs passed from `react-markdown`:
|
||||
*
|
||||
* 1. **Pre-processed SVGs**: Simple SVGs that were already handled by the
|
||||
* `rehypeScalableSvg` plugin. These are rendered directly with zero
|
||||
* performance overhead.
|
||||
* `rehypeScalableSvg` plugin. These are rendered directly.
|
||||
*
|
||||
* 2. **SVGs needing measurement**: Complex SVGs (e.g., with unit-based
|
||||
* dimensions like "100pt") are flagged with `data-needs-measurement`.
|
||||
* This component will perform a one-time, off-screen measurement for
|
||||
* these SVGs upon mounting to ensure they are rendered correctly and
|
||||
* scalably.
|
||||
* 2. **SVGs needing measurement**: Complex SVGs are flagged with
|
||||
* `data-needs-measurement`. This component performs a one-time DOM
|
||||
* mutation upon mounting to make them scalable. To prevent React from
|
||||
* reverting these changes during subsequent renders, it stops passing
|
||||
* the original `width` and `height` props after the mutation is complete.
|
||||
*/
|
||||
const MarkdownSvgRenderer: FC<SvgProps> = (props) => {
|
||||
const { 'data-needs-measurement': needsMeasurement, ...restProps } = props
|
||||
const svgRef = useRef<SVGSVGElement>(null)
|
||||
const [isMeasured, setIsMeasured] = useState(false)
|
||||
const isMeasuredRef = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (needsMeasurement && svgRef.current && !isMeasured) {
|
||||
// The element is a real DOM node, we can now measure it.
|
||||
if (needsMeasurement && svgRef.current && !isMeasuredRef.current) {
|
||||
// Directly mutate the DOM element to make it adaptive.
|
||||
makeSvgSizeAdaptive(svgRef.current)
|
||||
// Set flag to prevent re-measuring on subsequent renders
|
||||
setIsMeasured(true)
|
||||
// Set flag to prevent re-measuring. This does not trigger a re-render.
|
||||
isMeasuredRef.current = true
|
||||
}
|
||||
}, [needsMeasurement, isMeasured])
|
||||
}, [needsMeasurement])
|
||||
|
||||
// For SVGs that need measurement, we render them once with their original
|
||||
// props to allow the ref to capture the DOM element for measurement.
|
||||
// The `useEffect` will then trigger, process the element, and cause a
|
||||
// re-render with the correct scalable attributes.
|
||||
// For simple SVGs, they are rendered correctly from the start.
|
||||
return <svg ref={svgRef} {...restProps} />
|
||||
// Create a mutable copy of props to potentially modify.
|
||||
const finalProps = { ...restProps }
|
||||
|
||||
// If the SVG has been measured and mutated, we prevent React from
|
||||
// re-applying the original width and height attributes on subsequent renders.
|
||||
// This preserves the changes made by `makeSvgSizeAdaptive`.
|
||||
if (isMeasuredRef.current) {
|
||||
delete finalProps.width
|
||||
delete finalProps.height
|
||||
}
|
||||
|
||||
return <svg ref={svgRef} {...finalProps} />
|
||||
}
|
||||
|
||||
export default MarkdownSvgRenderer
|
||||
|
||||
Loading…
Reference in New Issue
Block a user