securingsincity / react-ace

React Ace Component
http://securingsincity.github.io/react-ace/
MIT License
4.02k stars 603 forks source link

Changing editor sessions causes session/selection listeners to stop firing #1839

Open sayomaki opened 11 months ago

sayomaki commented 11 months ago

Problem

When changing the session (Ace.EditSession) of the current editor (to allow for different editing sessions but reusing the same editor component) via the editor.setSession() method, the various session/selection related events stop firing

The events includes onCursorChange, onSelectionChange, onScroll, etc.

This could be due to the way how ReactAce implements event registration for the session-based events, as they are only registered during the componentDidMount lifecycle stage for the default session.

Sample code to reproduce your issue

The following code has been tested on react-ace@10.1.0, ace-builds@1.15.3, and on both react@16 and react@18.

import { useRef, useState } from 'react';
import ace, { createEditSession } from 'ace-builds';
import "ace-builds/webpack-resolver";
import AceEditor from 'react-ace';

import "ace-builds/src-noconflict/mode-javascript";
import "ace-builds/src-noconflict/ext-language_tools";

function App() {
  const aceEditorRef = useRef(null);
  const [cursorEvents, setCursorEvents] = useState(0);

  const changeSession = () => {
    const newSession = createEditSession('// new editor session\n// cursor event stops firing', 'ace/mode/javascript');
    if (aceEditorRef.current) {
      aceEditorRef.current.editor.setSession(newSession);
    }
  }

  const cursorChangeEvent = () => setCursorEvents(cursorEvents + 1);

  return (
    <div>
      <button onClick={changeSession}>Change editor session</button>
      <div>Cursor event fired: {cursorEvents} times</div>
      <AceEditor mode="ace/mode/javascript" onCursorChange={cursorChangeEvent} ref={aceEditorRef} />
    </div>
  );
}

export default App;

A simple but tedious workaround for the problem is to re-register the aforementioned events manually, right after changing sessions via editor.setSession(). However, care and caution is also needed to ensure the event is only registered once for each session, which leads to some very hacky fixes.

Possible resolution can be to track/intercept the session changes, and rebind the event listeners.

References