Disable UI rendering when history is skipped (#574)
When we are scrolling, resizing, or moving elements, we already disable the history. Since those actions do not change the state of the UI, we can also avoid re-drawing it and save ~10ms per frame. I had to change all the forceUpdate() to setState({}), otherwise it would bypass shouldComponentUpdate.
This commit is contained in:
parent
263fef4eaa
commit
8ab176b9a5
@ -180,7 +180,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
private syncActionResult = (res: ActionResult) => {
|
private syncActionResult = (res: ActionResult) => {
|
||||||
if (res.elements !== undefined) {
|
if (res.elements !== undefined) {
|
||||||
elements = res.elements;
|
elements = res.elements;
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.appState !== undefined) {
|
if (res.appState !== undefined) {
|
||||||
@ -199,7 +199,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
elements = deleteSelectedElements(elements);
|
elements = deleteSelectedElements(elements);
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
private onCopy = (e: ClipboardEvent) => {
|
private onCopy = (e: ClipboardEvent) => {
|
||||||
@ -226,6 +226,14 @@ export class App extends React.Component<any, AppState> {
|
|||||||
this.saveDebounced.flush();
|
this.saveDebounced.flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public shouldComponentUpdate() {
|
||||||
|
if (!history.isRecording()) {
|
||||||
|
this.componentDidUpdate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
document.addEventListener("copy", this.onCopy);
|
document.addEventListener("copy", this.onCopy);
|
||||||
document.addEventListener("paste", this.onPaste);
|
document.addEventListener("paste", this.onPaste);
|
||||||
@ -253,7 +261,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
if (data.appState) {
|
if (data.appState) {
|
||||||
this.setState(data.appState);
|
this.setState(data.appState);
|
||||||
} else {
|
} else {
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +283,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
public state: AppState = getDefaultAppState();
|
public state: AppState = getDefaultAppState();
|
||||||
|
|
||||||
private onResize = () => {
|
private onResize = () => {
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
};
|
};
|
||||||
|
|
||||||
private updateCurrentCursorPosition = (e: MouseEvent) => {
|
private updateCurrentCursorPosition = (e: MouseEvent) => {
|
||||||
@ -286,7 +294,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
private onKeyDown = (event: KeyboardEvent) => {
|
private onKeyDown = (event: KeyboardEvent) => {
|
||||||
if (event.key === KEYS.ESCAPE && !this.state.draggingElement) {
|
if (event.key === KEYS.ESCAPE && !this.state.draggingElement) {
|
||||||
elements = clearSelection(elements);
|
elements = clearSelection(elements);
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
this.setState({ elementType: "selection" });
|
this.setState({ elementType: "selection" });
|
||||||
if (window.document.activeElement instanceof HTMLElement) {
|
if (window.document.activeElement instanceof HTMLElement) {
|
||||||
window.document.activeElement.blur();
|
window.document.activeElement.blur();
|
||||||
@ -320,7 +328,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
}
|
}
|
||||||
return el;
|
return el;
|
||||||
});
|
});
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (
|
} else if (
|
||||||
shapesShortcutKeys.includes(event.key.toLowerCase()) &&
|
shapesShortcutKeys.includes(event.key.toLowerCase()) &&
|
||||||
@ -505,7 +513,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
elements = clearSelection(elements);
|
elements = clearSelection(elements);
|
||||||
document.documentElement.style.cursor =
|
document.documentElement.style.cursor =
|
||||||
value === "text" ? CURSOR_TYPE.TEXT : CURSOR_TYPE.CROSSHAIR;
|
value === "text" ? CURSOR_TYPE.TEXT : CURSOR_TYPE.CROSSHAIR;
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}}
|
}}
|
||||||
></ToolButton>
|
></ToolButton>
|
||||||
);
|
);
|
||||||
@ -695,7 +703,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
if (!element.isSelected) {
|
if (!element.isSelected) {
|
||||||
elements = clearSelection(elements);
|
elements = clearSelection(elements);
|
||||||
element.isSelected = true;
|
element.isSelected = true;
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextMenu.push({
|
ContextMenu.push({
|
||||||
@ -737,6 +745,8 @@ export class App extends React.Component<any, AppState> {
|
|||||||
let deltaY = lastY - e.clientY;
|
let deltaY = lastY - e.clientY;
|
||||||
lastX = e.clientX;
|
lastX = e.clientX;
|
||||||
lastY = e.clientY;
|
lastY = e.clientY;
|
||||||
|
// We don't want to save history when panning around
|
||||||
|
history.skipRecording();
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
scrollX: state.scrollX - deltaX,
|
scrollX: state.scrollX - deltaX,
|
||||||
scrollY: state.scrollY - deltaY,
|
scrollY: state.scrollY - deltaY,
|
||||||
@ -941,6 +951,8 @@ export class App extends React.Component<any, AppState> {
|
|||||||
if (isOverHorizontalScrollBar) {
|
if (isOverHorizontalScrollBar) {
|
||||||
const x = e.clientX - CANVAS_WINDOW_OFFSET_LEFT;
|
const x = e.clientX - CANVAS_WINDOW_OFFSET_LEFT;
|
||||||
const dx = x - lastX;
|
const dx = x - lastX;
|
||||||
|
// We don't want to save history when scrolling
|
||||||
|
history.skipRecording();
|
||||||
this.setState(state => ({ scrollX: state.scrollX - dx }));
|
this.setState(state => ({ scrollX: state.scrollX - dx }));
|
||||||
lastX = x;
|
lastX = x;
|
||||||
return;
|
return;
|
||||||
@ -949,6 +961,8 @@ export class App extends React.Component<any, AppState> {
|
|||||||
if (isOverVerticalScrollBar) {
|
if (isOverVerticalScrollBar) {
|
||||||
const y = e.clientY - CANVAS_WINDOW_OFFSET_TOP;
|
const y = e.clientY - CANVAS_WINDOW_OFFSET_TOP;
|
||||||
const dy = y - lastY;
|
const dy = y - lastY;
|
||||||
|
// We don't want to save history when scrolling
|
||||||
|
history.skipRecording();
|
||||||
this.setState(state => ({ scrollY: state.scrollY - dy }));
|
this.setState(state => ({ scrollY: state.scrollY - dy }));
|
||||||
lastY = y;
|
lastY = y;
|
||||||
return;
|
return;
|
||||||
@ -1051,7 +1065,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
lastY = y;
|
lastY = y;
|
||||||
// We don't want to save history when resizing an element
|
// We don't want to save history when resizing an element
|
||||||
history.skipRecording();
|
history.skipRecording();
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1072,7 +1086,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
lastY = y;
|
lastY = y;
|
||||||
// We don't want to save history when dragging an element to initially size it
|
// We don't want to save history when dragging an element to initially size it
|
||||||
history.skipRecording();
|
history.skipRecording();
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1127,7 +1141,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
}
|
}
|
||||||
// We don't want to save history when moving an element
|
// We don't want to save history when moving an element
|
||||||
history.skipRecording();
|
history.skipRecording();
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = (e: MouseEvent) => {
|
const onMouseUp = (e: MouseEvent) => {
|
||||||
@ -1152,12 +1166,11 @@ export class App extends React.Component<any, AppState> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
});
|
});
|
||||||
this.forceUpdate();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizeDimensions(draggingElement)) {
|
if (normalizeDimensions(draggingElement)) {
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resizingElement && isInvisiblySmallElement(resizingElement)) {
|
if (resizingElement && isInvisiblySmallElement(resizingElement)) {
|
||||||
@ -1188,7 +1201,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
if (draggingElement === null) {
|
if (draggingElement === null) {
|
||||||
// if no element is clicked, clear the selection and redraw
|
// if no element is clicked, clear the selection and redraw
|
||||||
elements = clearSelection(elements);
|
elements = clearSelection(elements);
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,7 +1221,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
history.resumeRecording();
|
history.resumeRecording();
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
};
|
};
|
||||||
|
|
||||||
lastMouseUp = onMouseUp;
|
lastMouseUp = onMouseUp;
|
||||||
@ -1218,7 +1231,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
|
|
||||||
// We don't want to save history on mouseDown, only on mouseUp when it's fully configured
|
// We don't want to save history on mouseDown, only on mouseUp when it's fully configured
|
||||||
history.skipRecording();
|
history.skipRecording();
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}}
|
}}
|
||||||
onDoubleClick={e => {
|
onDoubleClick={e => {
|
||||||
const { x, y } = viewportCoordsToSceneCoords(e, this.state);
|
const { x, y } = viewportCoordsToSceneCoords(e, this.state);
|
||||||
@ -1253,7 +1266,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
elements = elements.filter(
|
elements = elements.filter(
|
||||||
element => element.id !== elementAtPosition.id,
|
element => element.id !== elementAtPosition.id,
|
||||||
);
|
);
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
|
|
||||||
textX =
|
textX =
|
||||||
this.state.scrollX +
|
this.state.scrollX +
|
||||||
@ -1355,6 +1368,8 @@ export class App extends React.Component<any, AppState> {
|
|||||||
private handleWheel = (e: WheelEvent) => {
|
private handleWheel = (e: WheelEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { deltaX, deltaY } = e;
|
const { deltaX, deltaY } = e;
|
||||||
|
// We don't want to save history when panning around
|
||||||
|
history.skipRecording();
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
scrollX: state.scrollX - deltaX,
|
scrollX: state.scrollX - deltaX,
|
||||||
scrollY: state.scrollY - deltaY,
|
scrollY: state.scrollY - deltaY,
|
||||||
@ -1412,7 +1427,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
return duplicate;
|
return duplicate;
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
this.forceUpdate();
|
this.setState({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user