chore: fix leaking event listeners (#22562)

Fixes https://github.com/microsoft/playwright/issues/22348
This commit is contained in:
Pavel Feldman 2023-04-21 12:38:39 -07:00 committed by GitHub
parent f6aa9f49ce
commit becb072703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 13 deletions

View File

@ -104,6 +104,12 @@ export const Recorder: React.FC<RecorderProps> = ({
return () => document.removeEventListener('keydown', handleKeyDown);
}, [paused]);
const onEditorChange = React.useCallback((text: string) => {
setLocator(text);
const source = sources.find(s => s.id === fileId);
window.dispatch({ event: 'selectorUpdated', params: { selector: text, language: source?.language || 'javascript' } });
}, [sources, fileId]);
return <div className='recorder'>
<Toolbar>
<ToolbarButton icon='record' title='Record' toggled={mode === 'recording'} onClick={() => {
@ -139,10 +145,7 @@ export const Recorder: React.FC<RecorderProps> = ({
<ToolbarButton icon='microscope' title='Pick locator' toggled={mode === 'inspecting'} onClick={() => {
window.dispatch({ event: 'setMode', params: { mode: mode === 'inspecting' ? 'none' : 'inspecting' } }).catch(() => { });
}}>Pick locator</ToolbarButton>
<CodeMirrorWrapper text={locator} language={source.language} readOnly={false} focusOnChange={true} wrapLines={true} onChange={text => {
setLocator(text);
window.dispatch({ event: 'selectorUpdated', params: { selector: text, language: source.language } });
}} />
<CodeMirrorWrapper text={locator} language={source.language} readOnly={false} focusOnChange={true} wrapLines={true} onChange={onEditorChange} />
<ToolbarButton icon='files' title='Copy' onClick={() => {
copy(locator);
}}></ToolbarButton>

View File

@ -104,15 +104,9 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
codemirrorRef.current.cm.setSize(measure.width, measure.height);
}, [measure]);
React.useEffect(() => {
React.useLayoutEffect(() => {
if (!codemirror)
return;
codemirror.off('change', (codemirror as any).listenerSymbol);
(codemirror as any)[listenerSymbol] = undefined;
if (onChange) {
(codemirror as any)[listenerSymbol] = () => onChange(codemirror.getValue());
codemirror.on('change', (codemirror as any)[listenerSymbol]);
}
let valueChanged = false;
if (codemirror.getValue() !== text) {
@ -155,12 +149,22 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
codemirrorRef.current!.highlight = highlight;
codemirrorRef.current!.widgets = widgets;
}
// Line-less locations have line = 0, but they mean to reveal the file.
if (typeof revealLine === 'number' && codemirrorRef.current!.cm.lineCount() >= revealLine)
codemirror.scrollIntoView({ line: Math.max(0, revealLine - 1), ch: 0 }, 50);
let changeListener: () => void | undefined;
if (onChange) {
changeListener = () => onChange(codemirror.getValue());
codemirror.on('change', changeListener);
}
return () => {
if (changeListener)
codemirror.off('change', changeListener);
};
}, [codemirror, text, highlight, revealLine, focusOnChange, onChange]);
return <div className='cm-wrapper' ref={codemirrorElement}></div>;
};
const listenerSymbol = Symbol('listener');