DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on • Edited on • Originally published at thinkthroo.com

useSyncExternalStore usage in TipTap source code

In this article, we will review useSyncExternalStore usage in TipTap.

I found useSyncExternalStore is used in 3 files:

Before we look at these files, let’s learn what is useSyncExternalStore.

useSyncExternalStore

useSyncExternalStore is a React Hook that lets you subscribe to an external store.

Read more about useSyncExternalStore.

const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
Enter fullscreen mode Exit fullscreen mode

EditorContent.tsx

import { useSyncExternalStore } from 'use-sync-external-store/shim'
...
/**
 * This component renders all of the editor's node views.
 */
const Portals: React.FC<{ contentComponent: ContentComponent }> = ({
  contentComponent,
}) => {
  // For performance reasons, we render the node view portals on state changes only
  const renderers = useSyncExternalStore(
    contentComponent.subscribe,
    contentComponent.getSnapshot,
    contentComponent.getServerSnapshot,
  )

  // This allows us to directly render the portals without any additional wrapper
  return (
    <>
      {Object.values(renderers)}
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

Pay attention to the comment in this above code snippet:

For performance reasons, we render the node view portals on state changes only

useEditorState.ts

import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
...
/**
 * This hook allows you to watch for changes on the editor instance.
 * It will allow you to select a part of the editor state and re-render the component when it changes.
 * @example
 * ```

tsx
 * const editor = useEditor({...options})
 * const { currentSelection } = useEditorState({
 *  editor,
 *  selector: snapshot => ({ currentSelection: snapshot.editor.state.selection }),
 * })
 *

Enter fullscreen mode Exit fullscreen mode

*/
export function useEditorState(
options: UseEditorStateOptions | UseEditorStateOptions,
): TSelectorResult | null {
const [editorStateManager] = useState(() => new EditorStateManager(options.editor))

// Using the useSyncExternalStore hook to sync the editor instance with the component state
const selectedState = useSyncExternalStoreWithSelector(
editorStateManager.subscribe,
editorStateManager.getSnapshot,
editorStateManager.getServerSnapshot,
options.selector as UseEditorStateOptions['selector'],
options.equalityFn ?? deepEqual,
)

useIsomorphicLayoutEffect(() => {
return editorStateManager.watch(options.editor)
}, [options.editor, editorStateManager])

useDebugValue(selectedState)

return selectedState
}




> *Using the* `useSyncExternalStore` *hook to sync the editor instance with the component state*

In the `EditorContent.tsx`, the import was from `use-sync-external-store/shim` but here in this `useEditorState`, the import is from `use-sync-external-store/shim/with-selector`.

# **useEditor.ts**



```javascript
import { useSyncExternalStore } from 'use-sync-external-store/shim'
...
export function useEditor(
  options: UseEditorOptions = {},
  deps: DependencyList = [],
): Editor | null {
  const mostRecentOptions = useRef(options)

  mostRecentOptions.current = options

  const [instanceManager] = useState(() => new EditorInstanceManager(mostRecentOptions))

  const editor = useSyncExternalStore(
    instanceManager.subscribe,
    instanceManager.getEditor,
    instanceManager.getServerSnapshot,
  )

  useDebugValue(editor)
Enter fullscreen mode Exit fullscreen mode

Here the external store is instanceManager.

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles and videos.

I am open to working on interesting projects. Send me an email at ramu.narasinga@gmail.com

References:

  1. GitHub Search: useSyncExternalStore in tiptap
  2. EditorContent.tsx
  3. useEditorState.ts
  4. useEditor.ts
  5. React Docs: useSyncExternalStore

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay