Skip to content

Commit

Permalink
⚡️ Improve error handling performance
Browse files Browse the repository at this point in the history
We don't need a full rerender, we just clear the selection

ianstormtaylor/slate#5407 (comment)
  • Loading branch information
pajowu committed Aug 7, 2023
1 parent b71d196 commit a5d176c
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 29 deletions.
27 changes: 8 additions & 19 deletions frontend/src/editor/editor_error_boundary.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
// this file contains a hack to revive slate when it breaks because our other hacks kill it.
// se transcription_editor.tsx for how its used
// this file contains a hack to save slate when it breaks because our other hacks kill it.
// Slate raises exceptions when handling selections. We just ignore these errors and deselct

import React, { ReactNode } from 'react';
import { Editor, Transforms } from 'slate';

export const NeedsFullRender = React.createContext(false);

export class ErrorBoundary extends React.Component<{ children: ReactNode }, { error: boolean }> {
constructor(props: { children: ReactNode }) {
export class ErrorBoundary extends React.Component<{ children: ReactNode; editor: Editor }> {
constructor(props: { children: ReactNode; editor: Editor }) {
super(props);
this.state = { error: false };
}

static getDerivedStateFromError() {
return { error: true };
componentDidCatch() {
Transforms.deselect(this.props.editor);
}

render() {
if (this.state.error) {
setTimeout(() => {
this.setState({ error: false });
}, 0);
}
return (
<NeedsFullRender.Provider value={this.state.error}>
{this.props.children}
</NeedsFullRender.Provider>
);
return this.props.children;
}
}
14 changes: 4 additions & 10 deletions frontend/src/editor/transcription_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { useMediaQuery } from '../utils/use_media_query';
import { useSpeakerName } from '../utils/document';

import { useInView } from 'react-intersection-observer';
import { ErrorBoundary, NeedsFullRender } from './editor_error_boundary';
import { ErrorBoundary } from './editor_error_boundary';

export function formattedTime(sec: number | undefined): string {
if (sec === undefined) {
Expand All @@ -46,16 +46,10 @@ function Paragraph({ element, children, attributes }: RenderElementProps): JSX.E
const startAtom = element.children[0];
const speakerColors = useContext(SpeakerColorsContext);

/* This is a rather bad hack but saves A LOT of resources.
if an error is thrown, we catch it with our error boundary,
set needsRenderFull to true for one render and then set it to false again.
This way the editor is re-vived and we can still get the performance boost, this gives us.
*/
// This is a rather bad hack but saves A LOT of resources.
const { ref, inView } = useInView({
fallbackInView: true,
});
const needsFullRender = useContext(NeedsFullRender);
const renderFull = needsFullRender || inView;

const speakerChanged = useSlateSelector((editor) => {
const idx = ReactEditor.findPath(editor, element)[0];
Expand Down Expand Up @@ -163,7 +157,7 @@ function Paragraph({ element, children, attributes }: RenderElementProps): JSX.E
{/* If the paragraph is out of view, we do not render the children (which would the the text
leafs). Instead we just add the plain text of the paragraph here to enable search and
scrolling without jumping content. */}
{renderFull ? children : element.children.map((x) => x.text).join('')}
{inView ? children : element.children.map((x) => x.text).join('')}
</div>
</div>
);
Expand Down Expand Up @@ -252,7 +246,7 @@ export function TranscriptionEditor({
}}
>
<SpeakerColorsProvider>
<ErrorBoundary>
<ErrorBoundary editor={editor}>
<Editable
readOnly={readOnly}
renderElement={Paragraph}
Expand Down

0 comments on commit a5d176c

Please sign in to comment.