DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on

flushSync in TipTap source code

In this article, we will review a code snippet from TipTap source code.

Image description

As I was reading through the file, ReactRenderer.tsx, I saw a function named flushSync in the constructor. This below code snippet is written inside constructor.

if (this.editor.isInitialized) {
  // On first render, we need to flush the render synchronously
  // Renders afterwards can be async, but this fixes a cursor positioning issue
  flushSync(() => {
    this.render()
  })
} else {
  this.render()
}
Enter fullscreen mode Exit fullscreen mode

constructor

  /**
   * Immediately creates element and renders the provided React component.
   */
  constructor(component: ComponentType<R, P>, {
    editor,
    props = {},
    as = 'div',
    className = '',
  }: ReactRendererOptions) {
Enter fullscreen mode Exit fullscreen mode

This constructor, as the comment indicates, creates element and renders the provided React component.

Creating element

At line 106, document.createElement method is used to create the element.

this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
this.component = component
this.editor = editor as EditorWithContentComponent
this.props = props as P
this.element = document.createElement(as)
this.element.classList.add('react-renderer')

if (className) {
  this.element.classList.add(...className.split(' '))
}
Enter fullscreen mode Exit fullscreen mode

Rendering component

if (this.editor.isInitialized) {
  // On first render, we need to flush the render synchronously
  // Renders afterwards can be async, but this fixes a cursor 
  // positioning issue
  flushSync(() => {
    this.render()
  })
} else {
  this.render()
}
Enter fullscreen mode Exit fullscreen mode

The comment here explains why the flushSync API is used. It is to fix a cursor positioning issue, but what is flushSync?

flushSync

flushSync lets you force React to flush any updates inside the provided callback synchronously. This ensures that the DOM is updated immediately.

Read more about flushSync.

Using flushSync is uncommon and can hurt the performance of your app.

The below example is picked from React documentation.

Example

The browser onbeforeprint API allows you to change the page immediately before the print dialog opens. This is useful for applying custom print styles that allow the document to display better for printing. In the example below, you use flushSync inside of the onbeforeprint callback to immediately “flush” the React state to the DOM. Then, by the time the print dialog opens, isPrinting displays “yes”: — Source

import { useState, useEffect } from 'react';
import { flushSync } from 'react-dom';

export default function PrintApp() {
  const [isPrinting, setIsPrinting] = useState(false);

  useEffect(() => {
    function handleBeforePrint() {
      flushSync(() => {
        setIsPrinting(true);
      })
    }

    function handleAfterPrint() {
      setIsPrinting(false);
    }

    window.addEventListener('beforeprint', handleBeforePrint);
    window.addEventListener('afterprint', handleAfterPrint);
    return () => {
      window.removeEventListener('beforeprint', handleBeforePrint);
      window.removeEventListener('afterprint', handleAfterPrint);
    }
  }, []);

  return (
    <>
      <h1>isPrinting: {isPrinting ? 'yes' : 'no'}</h1>
      <button onClick={() => window.print()}>
        Print
      </button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Without flushSync, the print dialog will display isPrinting as “no”. This is because React batches the updates asynchronously and the print dialog is displayed before the state is updated. — Source

I tried commenting the flushSync and tested the print example. To my surprise, isPrinting is to set to yes when the flushSync is commented. I am not sure how flushSync makes a difference at this point.

Image description

Image description

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, videos.

I am open to work 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/@thinkthroo

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

References:

  1. https://github.com/ueberdosis/tiptap/blob/develop/packages/react/src/ReactRenderer.tsx#L116

  2. https://react.dev/reference/react-dom/flushSync

Top comments (0)