We’ve recently started an internal upgrade to codemirror 6. It’s coupled with a move away from angular to react - so really it’s a full rewrite. The initial challenge is working out which bits of state should live in codemirror and which bits should live in react and how to glue the two paradigms together.
For others using codemirror 6 with a react project I was wondering what hooks others have come up with to help? As well as sharing what we’ve found helpful. (linked conversation Suggestions for using with React workflow)
Here’s a hook that we’ve found particularly helpful.
function useExtension(view: EditorView, extensionCreator: () => Extension, deps: any[]) {
const compartment = useMemo(() => new Compartment(), []);
const extension = useMemo(extensionCreator, deps);
useEffect(() => {
if (!compartment.get(view.state)) {
view.dispatch({ effects: StateEffect.appendConfig.of(compartment.of(extension)) });
} else {
view.dispatch({ effects: compartment.reconfigure(extension) });
}
}, [view, extension]);
}
an example of its use would be a dynamic tabSize
export function useTabSize(view: EditorView, tabSize: number) {
useExtension(view, () => EditorState.tabSize.of(tabSize), [tabSize]);
}
If say you had a callback for doc changes, which was the return value of a useCallback
you could do something like.
export function useDocChanged(view: EditorView, callback: () => void) {
useExtension(
view,
() =>
EditorView.updateListener.of((update) => {
if (update.docChanged) callback();
}),
[callback]
);
}
We’ve also currently have a useEditorView
hook. And then a functional component to wrap the view
inside the dom.
export function useEditorView(initState: (() => EditorStateConfig) | EditorStateConfig = {}): EditorView {
const view = useMemo(
() => new EditorView({ state: EditorState.create(typeof initState === "function" ? initState() : initState) }),
[]
);
useEffect(() => () => view.destroy(), []);
return view;
}
github gist: Codemirror 6 with react · GitHub