atassis / react-codemirror-ts

Codemirror react wrapper made with typescript
MIT License
8 stars 1 forks source link

How can i reset the value? #8

Open darkmirrors opened 2 years ago

darkmirrors commented 2 years ago

I want to reset the editor value externally

import { Codemirror } from 'react-codemirror-ts'
import React, { FC, useEffect, useImperativeHandle, useState } from 'react'
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/material.css'
import 'codemirror/theme/neat.css'

interface IProps {
  name: string
  onChange?: (type: string, path: string) => void
  cRef: any
}

const CodemirrorComponent: FC<IProps> = ({ name, onChange, cRef }) => {
  const [value, setValue] = useState(' ')

  useImperativeHandle(cRef, () => ({
    changeVal: (newVal: string) => {
      console.log('here', newVal)

      setValue(newVal)
    },
  }))

  return (
    <Codemirror
      name="example"
      options={{
        lineNumbers: true,
        lineWrapping: true,
        mode: 'javascript',
        tabSize: 2,
        theme: 'material',
      }}
      onChange={(value: React.SetStateAction<string>, options: any) => {
        onChange && onChange(name, value as string)
        setValue(value)
      }}
      value={value}
    />
  )
}

export { CodemirrorComponent }

When I set value={value}, there are two problems

  1. The cursor returns to the first digit when you type
  2. After a few more inputs, the editor will loop forever

How to solve this problem?

atassis commented 2 years ago

Codemirror is a stateful editor, so it is not that great for a case you mention. You have to lookup through codemirrors docs, which are not that obvious.

revelt commented 1 year ago

Since this is a controlled component, the value is already set from outside. So, conceptually, all it takes to reset the value is to trigger setValue() with whatever new string.

For onChange function, you want to use useCallback. It's tricky to type it in one line, so I declare it separately, like this (I ended up using @uiw/react-codemirror which is more popular, but the gist should be the same here):

import { useState, useCallback } from "react";
import CodeMirror from "@uiw/react-codemirror";
import type { ReactCodeMirrorProps } from "@uiw/react-codemirror";
import { html } from "@codemirror/lang-html";
import { EditorView } from "@codemirror/view";
...

const [inputStr, setInputStr] = useState("");
const onChangeFn: ReactCodeMirrorProps["onChange"] = (value, viewUpdate) => {
    setInputStr(value);
};
const onChange = useCallback(onChangeFn, []);

return (
    <CodeMirror
        className="cm-outer-container"
        value={inputStr}
        height="200px"
        extensions={[html(), EditorView.lineWrapping]}
        readOnly={true}
    />
)