jsoneditor-react: Editor doesn't rerender when I change the 'value' props

I am using two editors at same time. An update in one editor should update the second one and viceversa. I have used same state variable in both editors and i have handled onChange in both editors by changing the state variable jsonData. Still when I change JSON data in one editor the other one doesn’t rerender. It remains same. The following is my code:

`<div> <Editor value={this.state.jsonData} ajv={ajv} onChange={ (jsonData) => this.setState({ jsonData }) } search={false} navigationBar={false} /> <Editor value={this.state.jsonData} onChange={ (jsonData) => this.setState({ jsonData }) } mode=“code” />

</div>`

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 3
  • Comments: 26 (8 by maintainers)

Most upvoted comments

@vankop thank you so much for your answer!

const JsonEditor = ({ data = {}, handleJSON}) => {
  const jsonEditorRef = useRef(null)

  useEffect(() => {
    if (jsonEditorRef.current !== null) {
      jsonEditorRef.current.set(data);
    }
  }, [data])

  const setRef = instance => {
    if (instance) {
      jsonEditorRef.current = instance.jsonEditor;
    } else {
      jsonEditorRef.current = null;
    }
  };

  return (
    <Editor
      ref={setRef}
      value={data}
      onChange={handleJSON}
      search={false}
      statusBar={true}
      mode='code'
      htmlElementProps={{
        style: {
          height: 500
        },
      }}
    />
  );
} 

You can simply pass the key in the editor which makes it to re-render whenever the key values changes. I did like this:

<Editor key={props.value.type} {...props}

PS: Don’t pass object for key since it will be converted as [object Object] and remains same even if values change. In my code props.value is an object and props.value.type is a string. so the editor re renders with new value for every value change, whereas type is a unique value.

@markdemich you need to get ref of <JsonEditor /> to get access to editor instance explicitly. For instance:

class YourComponent extends React.Component {
   setRef = instance => {
         if (instance) {
                const {jsonEditor} = instance;
               this.jsonEditor = jsonEditor;
         } else {
               this.jsonEditor = null;
         }
   };

  render() {
     return (
          <Editor
                     ref={this.setRef}
             />
    );
  }
}

then you can do what ever you want with jsonEditor using api

I ended up rewriting this component myself using jsoneditor directly instead of depending on jsoneditor-react. It’s actually very simple. I’d like to share this but I’m not using Javascript, I’m using Scala and it looks like this:

import "jsoneditor/dist/jsoneditor.min.css";

object JsonEditor {
  val component = FunctionalComponent[Props] { props =>
    val classes = useStyles()

    val (editor, updateEditor) = useState(null)
    val editorRef              = React.createRef[HTMLLabelElement]
    useEffect(
      () =>
        updateEditor(
          new JSONEditor(
            editorRef.current,
            {
              mode: props.mode,
              modes: props.modes.map(_.toJSArray),
              onChange: props.onChange,
              onChangeText: props.onChangeText
              // TODO Add all the options here
            },
            JSON.parse(props.value)
          )
        ),
      Seq.empty
    )
    useEffect(() => if (editor != null) editor.updateText(props.value), Seq(props.value))

    div(ref := editorRef, className := classes.editor)
  }
}

I also noticed you can avoid users of this lib to have to import "jsoneditor/dist/jsoneditor.min.css"; by adding the import in your component and configure your webpack as:

module.exports = {
  module: {
    rules: [
      { test: new RegExp("\\.css$"), loader: ["style-loader", "css-loader"] }
    ]
  }
}

<JsonEditor /> is uncontrolled component, so value property is only initial value of json editor. If your task is to use both values in 2 editors you need explicitly get jsoneditors.

For instance:

class YourComponent extends React.Component {
   set1EditorRef = instance => this.editor1 = instance;
   set2EditorRef = instance => this.editor2 = instance;

  1editorChangeHandler = jsonData => {
           this.setState({ jsonData });
          this.editor2.jsonEditor.set(jsonData);
   };

  2editorChangeHandler = jsonData => {
           this.setState({ jsonData });
          this.editor1.jsonEditor.set(jsonData);
   };

  render() {
     return [
           <Editor
                  ref={this.set1EditorRef}
                    value={this.state.jsonData}
                   ajv={ajv}
                   onChange={this.1editorChangeHandler}
                   search={false}
                   navigationBar={false}
             />
            <Editor
                     ref={this.set2EditorRef}
                     value={this.state.jsonData}
                     onChange={this.2editorChangeHandler}
                     mode="code"
             />
     ];
  }
}