Home > Software design >  Adding updated state to code editor only works once
Adding updated state to code editor only works once

Time:10-26

I have an issue with my code below. When you click the add code button, it adds the code to the monaco code editor which is great. However, if you type some more code in the editor or erase whats currently there and then press the 'Add code' button, nothing is added. It's just blank.

Is there a way to whenever that 'Add code' button is clicked it clears everything in the editor and just adds the setAddCode state when the button is clicked?

And here is the code:

import { useState, useRef, useEffect } from "react";
import Editor from "@monaco-editor/react";

export default function IndexPage() {
  const [input, setInput] = useState("");
  const [addCode, setAddCode] = useState("# code goes here");

  const editorRef = useRef(null);

  function handleEditorDidMount(editor, monaco) {
    setInput((editorRef.current = editor));
    editorRef.current = editor;
  }

  return (
    <div>
      <div className="code-editor">
        <Editor
          width="100vh"
          height="40vh"
          theme="vs-dark"
          fontSize="14"
          defaultLanguage="python"
          defaultValue=""
          value={addCode}
          onMount={handleEditorDidMount}
        />
      </div>
      <br />
      <button onClick={() => setAddCode("print('Hello World!')")}>
        Add code
      </button>
    </div>
  );
}

CodePudding user response:

The way the Editor component is set up, it will only change the value in the editor if you pass a different value prop. It's probably doing something similar to the following:

const Editor = ({ value }) => {
  const [codeToDisplay, setCodeToDisplay] = useState(value);
  useEffect(() => {
    setCodeToDisplay(value);
  }, [value]);
  // etc

In your parent component, when you call setAddCode("print('Hello World!')") the first time, that'll result in the child component seeing a difference in how it was called - the value prop changed - so it'll know that there's something different to display, and update its own internal state appropriately. When you press the button again, the addCode value will stay the same - the Editor component doesn't see any difference, so it won't update.

To fix it, you can listen for changes from inside Editor by using its onchange prop to update the state in the parent component when the code inside the editor changes - that way, when you click the button later, the prop will be different, and the editor will know to update its internal state.

export default function IndexPage() {
  const [input, setInput] = useState("");
  const [codeValue, setCodeValue] = useState("# code goes here");

  const editorRef = useRef(null);

  function handleEditorDidMount(editor, monaco) {
    setInput((editorRef.current = editor));
    editorRef.current = editor;
  }

  return (
    <div>
      <div className="code-editor">
        <Editor
          width="100vh"
          height="40vh"
          theme="vs-dark"
          fontSize="14"
          defaultLanguage="python"
          defaultValue=""
          value={codeValue}
          onChange={(newValue) => { setCodeValue(newValue); }}
          onMount={handleEditorDidMount}
        />
      </div>
      <br />
      <button onClick={() => setCodeValue("print('Hello World!')")}>
        Add code
      </button>
    </div>
  );
}
  • Related