securingsincity / react-ace

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

Ace editor only binds commands on mount #684

Open BenBrewerBowman opened 5 years ago

BenBrewerBowman commented 5 years ago

Problem

If you pass a prop function to react-ace, it will only bind the function at the AceEditor mount. If your function prop changes, it won't use your new changed function, only the one passed in upon the first mount.

Detail the problem here, including any possible solutions.

Sample code to reproduce your issue

(Ignore the error) Edit relaxed-goldwasser-qprrd

References

Progress on: #

juancarlosfarah commented 5 years ago

I bumped into this issue and got around it by getting the value from the Editor that is passed to the command using getValue().

So in your case you would change the handleSubmit function.

const handleSubmit = (editor) => {
  const text = editor.getValue();
  window.alert("You submitted the text: " + text);
};

https://codesandbox.io/s/confident-neumann-99zmk

BenBrewerBowman commented 5 years ago

Thanks for workaround! That is a decent temporary solution, but it still doesn't solve the root problem. You shouldn't be forced to pass the entire editor object to the parent. The Ace Editor component shouldn't only bind your commands on mounting. If you change the commands being passed in, it should update the component with your updated commands.

0b5vr commented 4 years ago

Current workaround in function components is to use useRef and assign the () => referencedFunction.current() instead as exec

pavsidhu commented 4 years ago

@FMS-Cat how did you get this working? Using the following example I tried, it doesn't seem to work as a solution?

function Example() {
    function save() { ... }

    const ref = useRef(save)

    return (
      <AceEditor commands={[
        {
          name: 'save',
          bindKey: {
            win: 'Ctrl-enter',
            mac: 'Cmd-enter',
          },
          exec: () => ref.current(),
        },
      ]}/>
    )
}
dcunning commented 4 years ago

Until this is fixed, here's more code for two workarounds discussed above

editor.getValue() [cleaner workaround]

// `onSave` shouldn't have to pass the content 
// back up the chain since onChange already did that,
// hence calling this a workaround.
function Example({ content, onChange, onSave }) {
  return (
    <AceEditor
      content={content}
      onChange={c => onChange(c)}
      commands={[{
        name: 'save',
        bindKey: { win: 'Ctrl-enter', mac: 'Cmd-enter' },
        exec: editor => onSave(editor.getValue()),
      }]}
    />
  );
}

useRef

function Example({ content, onChange, onSave }) {
  const editor = useRef(null)

  return (
    <AceEditor
      ref={editor}
      content={content}
      onChange={c => onChange(c)}
      commands={[{
        name: 'save',
        bindKey: { win: 'Ctrl-enter', mac: 'Cmd-enter' },
        exec: () => onSave(editor.current.props.value),
      }]}
    />
  );
}
Cihatata commented 2 years ago

Do you have any updates 👀 ?