React hooks

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

Not sure if it helps but I’ve found rodemirror particularly useful for myself : GitHub - sachinraja/rodemirror: React component for CodeMirror 6

and a simplified variant for my own usecase is here:

1 Like