prevent unnecessary re-rendering of rountangles and diamonds
This commit is contained in:
parent
0fc3775a11
commit
2ca2ba5d1b
5 changed files with 45 additions and 12 deletions
|
|
@ -23,3 +23,18 @@ export function memoize<InType,OutType>(fn: (i: InType) => OutType) {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// compare arrays by value
|
||||
export function arraysEqual<T>(a: T[], b: T[], cmp: (a: T, b: T) => boolean = (a,b)=>a===b): boolean {
|
||||
if (a === b)
|
||||
return true;
|
||||
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
|
||||
for (let i=0; i<a.length; i++)
|
||||
if (!cmp(a[i],b[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { rountangleMinSize } from "./VisualEditor";
|
|||
import { Vec2D } from "./geometry";
|
||||
import { RectHelper } from "./RectHelpers";
|
||||
import { memo } from "react";
|
||||
import { arraysEqual } from "@/App/util";
|
||||
|
||||
export const DiamondShape = memo(function DiamondShape(props: {size: Vec2D, extraAttrs: object}) {
|
||||
const minSize = rountangleMinSize(props.size);
|
||||
|
|
@ -20,12 +21,13 @@ export const DiamondShape = memo(function DiamondShape(props: {size: Vec2D, extr
|
|||
/>;
|
||||
});
|
||||
|
||||
export const DiamondSVG = memo(function DiamondSVG(props: { diamond: Diamond; selected: string[]; highlight: RountanglePart[]; errors: string[]; active: boolean; }) {
|
||||
export const DiamondSVG = memo(function DiamondSVG(props: { diamond: Diamond; selected: RountanglePart[]; highlight: RountanglePart[]; error?: string; active: boolean; }) {
|
||||
console.log('render diamond', props.diamond.uid);
|
||||
const minSize = rountangleMinSize(props.diamond.size);
|
||||
const extraAttrs = {
|
||||
className: ''
|
||||
+ (props.selected.length === 4 ? " selected" : "")
|
||||
+ (props.errors.length > 0 ? " error" : "")
|
||||
+ (props.error ? " error" : "")
|
||||
+ (props.active ? " active" : ""),
|
||||
"data-uid": props.diamond.uid,
|
||||
"data-parts": "left top right bottom",
|
||||
|
|
@ -39,4 +41,10 @@ export const DiamondSVG = memo(function DiamondSVG(props: { diamond: Diamond; se
|
|||
|
||||
<RectHelper uid={props.diamond.uid} size={minSize} highlight={props.highlight} selected={props.selected} />
|
||||
</g>;
|
||||
}, (prevProps, nextProps) => {
|
||||
return prevProps.diamond === nextProps.diamond
|
||||
&& arraysEqual(prevProps.selected, nextProps.selected)
|
||||
&& arraysEqual(prevProps.highlight, nextProps.highlight)
|
||||
&& prevProps.error === nextProps.error
|
||||
&& prevProps.active === nextProps.active
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ function lineGeometryProps(size: Vec2D): [RountanglePart, object][] {
|
|||
];
|
||||
}
|
||||
|
||||
export const RectHelper = memo(function RectHelper(props: { uid: string, size: Vec2D, selected: string[], highlight: RountanglePart[] }) {
|
||||
// no need to memo() this component, the parent component is already memoized
|
||||
export const RectHelper = function RectHelper(props: { uid: string, size: Vec2D, selected: RountanglePart[], highlight: string[] }) {
|
||||
const geomProps = lineGeometryProps(props.size);
|
||||
return <>
|
||||
{geomProps.map(([side, ps]) => <g key={side}>
|
||||
|
|
@ -54,4 +55,4 @@ export const RectHelper = memo(function RectHelper(props: { uid: string, size: V
|
|||
data-uid={props.uid}
|
||||
data-parts="bottom left" />
|
||||
</>;
|
||||
});
|
||||
};
|
||||
|
|
@ -3,9 +3,12 @@ import { Rountangle, RountanglePart } from "../statecharts/concrete_syntax";
|
|||
import { ROUNTANGLE_RADIUS } from "./parameters";
|
||||
import { RectHelper } from "./RectHelpers";
|
||||
import { rountangleMinSize } from "./VisualEditor";
|
||||
import { arraysEqual } from "@/App/util";
|
||||
|
||||
|
||||
export const RountangleSVG = memo(function RountangleSVG(props: {rountangle: Rountangle; selected: string[]; highlight: RountanglePart[]; errors: string[]; active: boolean; }) {
|
||||
export const RountangleSVG = memo(function RountangleSVG(props: {rountangle: Rountangle; selected: RountanglePart[]; highlight: RountanglePart[]; error?: string; active: boolean; }) {
|
||||
console.log('render rountangle', props.rountangle.uid);
|
||||
|
||||
const { topLeft, size, uid } = props.rountangle;
|
||||
// always draw a rountangle with a minimum size
|
||||
// during resizing, rountangle can be smaller than this size and even have a negative size, but we don't show it
|
||||
|
|
@ -14,7 +17,7 @@ export const RountangleSVG = memo(function RountangleSVG(props: {rountangle: Rou
|
|||
className: 'rountangle'
|
||||
+ (props.selected.length === 4 ? " selected" : "")
|
||||
+ (' ' + props.rountangle.kind)
|
||||
+ (props.errors.length > 0 ? " error" : "")
|
||||
+ (props.error ? " error" : "")
|
||||
+ (props.active ? " active" : ""),
|
||||
"data-uid": uid,
|
||||
"data-parts": "left top right bottom",
|
||||
|
|
@ -31,11 +34,17 @@ export const RountangleSVG = memo(function RountangleSVG(props: {rountangle: Rou
|
|||
|
||||
<text x={10} y={20} className="uid">{props.rountangle.uid}</text>
|
||||
|
||||
{(props.errors.length > 0) &&
|
||||
<text className="error" x={10} y={40} data-uid={uid} data-parts="left top right bottom">{props.errors.join(' ')}</text>}
|
||||
{props.error &&
|
||||
<text className="error" x={10} y={40} data-uid={uid} data-parts="left top right bottom">{props.error}</text>}
|
||||
|
||||
<RectHelper uid={uid} size={minSize}
|
||||
selected={props.selected}
|
||||
highlight={props.highlight} />
|
||||
</g>;
|
||||
}, (prevProps, nextProps) => {
|
||||
return prevProps.rountangle === nextProps.rountangle
|
||||
&& arraysEqual(prevProps.selected, nextProps.selected)
|
||||
&& arraysEqual(prevProps.highlight, nextProps.highlight)
|
||||
&& prevProps.error === nextProps.error
|
||||
&& prevProps.active === nextProps.active
|
||||
})
|
||||
|
|
|
|||
|
|
@ -718,9 +718,9 @@ export const VisualEditor = memo(function VisualEditor({state, setState, setAST,
|
|||
rountangle={rountangle}
|
||||
selected={selection.find(r => r.uid === rountangle.uid)?.parts || []}
|
||||
highlight={[...(sidesToHighlight[rountangle.uid] || []), ...(rountanglesToHighlight[rountangle.uid]?["left","right","top","bottom"]:[]) as RountanglePart[]]}
|
||||
errors={errors
|
||||
error={errors
|
||||
.filter(({shapeUid}) => shapeUid === rountangle.uid)
|
||||
.map(({message}) => message)}
|
||||
.map(({message}) => message).join(', ')}
|
||||
active={highlightActive.has(rountangle.uid)}
|
||||
/>})}
|
||||
|
||||
|
|
@ -730,9 +730,9 @@ export const VisualEditor = memo(function VisualEditor({state, setState, setAST,
|
|||
diamond={diamond}
|
||||
selected={selection.find(r => r.uid === diamond.uid)?.parts || []}
|
||||
highlight={[...(sidesToHighlight[diamond.uid] || []), ...(rountanglesToHighlight[diamond.uid]?["left","right","top","bottom"]:[]) as RountanglePart[]]}
|
||||
errors={errors
|
||||
error={errors
|
||||
.filter(({shapeUid}) => shapeUid === diamond.uid)
|
||||
.map(({message}) => message)}
|
||||
.map(({message}) => message).join(', ')}
|
||||
active={false}/>
|
||||
</>)}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue