uiwjs / react-codemirror

CodeMirror 6 component for React. @codemirror https://uiwjs.github.io/react-codemirror/
https://uiwjs.github.io/react-codemirror/
MIT License
1.5k stars 125 forks source link

Using this as a "controlled" component? #273

Open wardellbagby opened 2 years ago

wardellbagby commented 2 years ago

Is it possible to move the state out of the React component and instead always provide it as a prop? I.e., making it controlled vs its current uncontrolled?

https://reactjs.org/docs/uncontrolled-components.html https://reactjs.org/docs/forms.html#controlled-components

jaywcjlove commented 2 years ago

Which states need to be removed and used as props? @wardellbagby

wardellbagby commented 2 years ago

To make it a controlled component?

Well, that's kind of where the issue is; I'm not entirely sure.

What I'm looking for is a way to just give this an EditorState and let the component render that EditorState to an EditorView.

That itself is really simple, but solving issues like "is this a brand new state and therefore should use setState or should it be dispatched as an array of Transactions has be pretty unsure. So I wanted to see if y'all had any thoughts around it?

sfmcintyre commented 2 years ago

also interested in controlling state from outside of this component; in particular, managing the value to validate code externally, and a few other props to dynamically add and style elements within the editor (error messages in gutters, etc)

one issue i'm seeing with the controlled flow is: whenever a prop passed into useCodeMirror is changed, there's a flash from an unmount & remount of the autocompletion tooltip

here's a repro where you can see the behavior – in this case, each keystroke when typing to change the value of the controlled component causes a flash (type 'func' to get the relevant js autocomplete)

this may be an issue with or improper usage of core codemirror packages (perhaps here in the TooltipViewManager?), but curious if anyone has a similar use case, a fix at either the react-codemirror or codemirror-level, or any other thoughts, i'd love to hear!

tomerlichtash commented 1 year ago

Is it possible to move the state out of the React component and instead always provide it as a prop? I.e., making it controlled vs its current uncontrolled?

Did you have any luck in doing so in the meanwhile?

the-watchmaker commented 1 year ago

Same here. I need a "controlled" component.

tomerlichtash commented 1 year ago

@the-watchmaker Turns out there're not many open source solutions out there for a well behaved controlled CM in React. After some research I ended up following a this article as a guide, using a custom onChange method and a hook to achieve a controlled state.

the-watchmaker commented 1 year ago

@tomerlichtash Thanks for the link. I solved most of the issues by using EditorState.changeFilter and EditorState.transactionFilter in extensions prop to filter or mutate the input.

Lilke this:

<CodeMirror
    //...
    extensions={[
      EditorState.changeFilter.of(handleLimitDocLength),
    ]}
  />

I think most of time this is what we want to achieve as a React dev User input -> update input state -> mutate input state using useMemo or useEffect -> update input state -> rerender with thew new input

But my workaround in this case with Codemirror was: User input -> intercept input and do your stuff with EditorState.changeFilter and EditorState.transactionFilter -> update state -> rerender

This is a typical case where not everything is in React way. Especially when you work with libs that came before it.

I find 90% of the time, DIY React integration with the 3rd party lib is the way to go. But this was for my pet project. I wouldn't bother.