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?)
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)}
    </>
  )
}
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 }),
 * })
 *
*/
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)
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
- My Github — https://github.com/ramu-narasinga
- My website — https://ramunarasinga.com
- My Youtube channel — https://www.youtube.com/@ramu-narasinga
- Learning platform — https://thinkthroo.com
- Codebase Architecture — https://app.thinkthroo.com/architecture
- Best practices — https://app.thinkthroo.com/best-practices
- Production-grade projects — https://app.thinkthroo.com/production-grade-projects
 


 
    
Top comments (0)