Skip to content

Commit

Permalink
fix: Fix echo onChange call when value prop is changed (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
11bit authored Feb 9, 2023
1 parent 075531a commit 7637bff
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
7 changes: 7 additions & 0 deletions core/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,10 @@ it('CodeMirror editable', async () => {
expect(text.className).toEqual('cm-content');
expect(text.tagName).toEqual('DIV');
});

it("CodeMirror doesn't echo changes", async () => {
const handleChange = jest.fn();
const { rerender } = render(<CodeMirror value="value a" onChange={handleChange} />);
rerender(<CodeMirror value="value b" onChange={handleChange} />);
expect(handleChange).not.toHaveBeenCalled();
});
13 changes: 11 additions & 2 deletions core/src/useCodeMirror.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useEffect, useState } from 'react';
import { EditorState, StateEffect } from '@codemirror/state';
import { Annotation, EditorState, StateEffect } from '@codemirror/state';
import { indentWithTab } from '@codemirror/commands';
import { EditorView, keymap, ViewUpdate, placeholder } from '@codemirror/view';
import { basicSetup } from '@uiw/codemirror-extensions-basic-setup';
import { oneDark } from '@codemirror/theme-one-dark';
import { getStatistics } from './utils';
import { ReactCodeMirrorProps } from '.';

const External = Annotation.define<boolean>();

export interface UseCodeMirror extends ReactCodeMirrorProps {
container?: HTMLDivElement | null;
}
Expand Down Expand Up @@ -60,7 +62,13 @@ export function useCodeMirror(props: UseCodeMirror) {
},
});
const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => {
if (vu.docChanged && typeof onChange === 'function') {
if (
vu.docChanged &&
typeof onChange === 'function' &&
// Fix echoing of the remote changes:
// If transaction is market as remote we don't have to call `onChange` handler again
!vu.transactions.some((tr) => tr.annotation(External))
) {
const doc = vu.state.doc;
const value = doc.toString();
onChange(value, vu);
Expand Down Expand Up @@ -188,6 +196,7 @@ export function useCodeMirror(props: UseCodeMirror) {
if (view && value !== currentValue) {
view.dispatch({
changes: { from: 0, to: currentValue.length, insert: value || '' },
annotations: [External.of(true)],
});
}
}, [value, view]);
Expand Down

0 comments on commit 7637bff

Please sign in to comment.