fix: React.memo resolvers not accounting for all props (#6042)
This commit is contained in:
parent
06b45e0cfc
commit
618442299f
@ -15,7 +15,11 @@ import {
|
||||
BinaryFiles,
|
||||
UIChildrenComponents,
|
||||
} from "../types";
|
||||
import { muteFSAbortError, ReactChildrenToObject } from "../utils";
|
||||
import {
|
||||
isShallowEqual,
|
||||
muteFSAbortError,
|
||||
ReactChildrenToObject,
|
||||
} from "../utils";
|
||||
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
||||
import CollabButton from "./CollabButton";
|
||||
import { ErrorDialog } from "./ErrorDialog";
|
||||
@ -496,28 +500,39 @@ const LayerUI = ({
|
||||
);
|
||||
};
|
||||
|
||||
const areEqual = (prev: LayerUIProps, next: LayerUIProps) => {
|
||||
const getNecessaryObj = (appState: AppState): Partial<AppState> => {
|
||||
const {
|
||||
suggestedBindings,
|
||||
startBoundElement: boundElement,
|
||||
...ret
|
||||
} = appState;
|
||||
return ret;
|
||||
};
|
||||
const prevAppState = getNecessaryObj(prev.appState);
|
||||
const nextAppState = getNecessaryObj(next.appState);
|
||||
const stripIrrelevantAppStateProps = (
|
||||
appState: AppState,
|
||||
): Partial<AppState> => {
|
||||
const { suggestedBindings, startBoundElement, cursorButton, ...ret } =
|
||||
appState;
|
||||
return ret;
|
||||
};
|
||||
|
||||
const keys = Object.keys(prevAppState) as (keyof Partial<AppState>)[];
|
||||
const areEqual = (prevProps: LayerUIProps, nextProps: LayerUIProps) => {
|
||||
// short-circuit early
|
||||
if (prevProps.children !== nextProps.children) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
canvas: _prevCanvas,
|
||||
// not stable, but shouldn't matter in our case
|
||||
onInsertElements: _prevOnInsertElements,
|
||||
appState: prevAppState,
|
||||
...prev
|
||||
} = prevProps;
|
||||
const {
|
||||
canvas: _nextCanvas,
|
||||
onInsertElements: _nextOnInsertElements,
|
||||
appState: nextAppState,
|
||||
...next
|
||||
} = nextProps;
|
||||
|
||||
return (
|
||||
prev.renderTopRightUI === next.renderTopRightUI &&
|
||||
prev.renderCustomStats === next.renderCustomStats &&
|
||||
prev.renderCustomSidebar === next.renderCustomSidebar &&
|
||||
prev.langCode === next.langCode &&
|
||||
prev.elements === next.elements &&
|
||||
prev.files === next.files &&
|
||||
keys.every((key) => prevAppState[key] === nextAppState[key])
|
||||
isShallowEqual(
|
||||
stripIrrelevantAppStateProps(prevAppState),
|
||||
stripIrrelevantAppStateProps(nextAppState),
|
||||
) && isShallowEqual(prev, next)
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useEffect, forwardRef } from "react";
|
||||
import { InitializeApp } from "../../components/InitializeApp";
|
||||
import App from "../../components/App";
|
||||
import { isShallowEqual } from "../../utils";
|
||||
|
||||
import "../../css/app.scss";
|
||||
import "../../css/styles.scss";
|
||||
@ -128,6 +129,11 @@ const areEqual = (
|
||||
prevProps: PublicExcalidrawProps,
|
||||
nextProps: PublicExcalidrawProps,
|
||||
) => {
|
||||
// short-circuit early
|
||||
if (prevProps.children !== nextProps.children) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
initialData: prevInitialData,
|
||||
UIOptions: prevUIOptions = {},
|
||||
@ -176,13 +182,7 @@ const areEqual = (
|
||||
return true;
|
||||
});
|
||||
|
||||
const prevKeys = Object.keys(prevProps) as (keyof typeof prev)[];
|
||||
const nextKeys = Object.keys(nextProps) as (keyof typeof next)[];
|
||||
return (
|
||||
isUIOptionsSame &&
|
||||
prevKeys.length === nextKeys.length &&
|
||||
prevKeys.every((key) => prev[key] === next[key])
|
||||
);
|
||||
return isUIOptionsSame && isShallowEqual(prev, next);
|
||||
};
|
||||
|
||||
const forwardedRefComp = forwardRef<
|
||||
|
12
src/utils.ts
12
src/utils.ts
@ -709,3 +709,15 @@ export const ReactChildrenToObject = <
|
||||
return acc;
|
||||
}, {} as Partial<T>);
|
||||
};
|
||||
|
||||
export const isShallowEqual = <T extends Record<string, any>>(
|
||||
objA: T,
|
||||
objB: T,
|
||||
) => {
|
||||
const aKeys = Object.keys(objA);
|
||||
const bKeys = Object.keys(objA);
|
||||
if (aKeys.length !== bKeys.length) {
|
||||
return false;
|
||||
}
|
||||
return aKeys.every((key) => objA[key] === objB[key]);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user