Performance issue: Handsontable slow when React re-renders the component

Hi,

I’ve embedded Handsontable inside a React component.
As expected in React, whenever state changes (either in the parent or inside this component), React re-renders the component that contains <HotTable>.

The problem is that during these re-renders Handsontable takes a long time to update — it feels like the main thread is blocked for 1-2 seconds whenever the component with <HotTable> re-renders, and Chrome DevTools shows warnings such as

[Violation] ‘message’ handler took ~500ms
[Violation] Forced reflow while executing JavaScript took ms
[Violation] ‘change’ handler took ~600ms

I’ve disabled autoRowSize and autoColumnSize, and set viewportRowRenderingOffset={20}, but the issue persists.

Is there a recommended way to structure a Handsontable React wrapper to minimize expensive updates when React state changes?

Are there patterns that help avoid full re-renders on every state update?

Thanks for your help!

Hi @jaseelkaderi.officia

Thank you for contacting us. We only have a general optimization tips: Performance - React Data Grid | Handsontable

Can you please share the code demo where we can observe this issue? It will be easier to recommend something this way.

Below is a shortened piece of code where I am facing this issue (in my actual implementation I am doing more customizations, but the problem occurs in the same way):

import React, { useRef, useState, useMemo, useEffect, useCallback } from "react";
import { HotTable } from "@handsontable/react";
import { registerAllModules } from "handsontable/registry";

registerAllModules();



const CustomHandsontable= ({ headers, data }) => {
  const hotRef = useRef(null);
  const [selectedRows, setSelectedRows] = useState<Record<number, boolean>>({});

  const afterGetRowHeader = (row: number, th: HTMLElement) => {
    th.innerHTML = "";
    const input = document.createElement("input");
    input.type = "checkbox";
    input.checked = !!selectedRows[row];
    input.addEventListener("change", () => {
      setSelectedRows((prev) => ({
        ...prev,
        [row]: !prev[row],
      }));
    });
    th.appendChild(input);
  };



  return (
    <div style={{ position: "relative" }}>
      <HotTable
        ref={hotRef}
        data={data}
        rowHeaders={true}
        columns={columns}
        licenseKey="non-commercial-and-evaluation"
        afterGetRowHeader={afterGetRowHeader}
        className="custom-hot ht-theme-horizon"
        stretchH="all"
        width="100%"
        viewportRowRenderingOffset={20}
      />
    </div>
  );
};

export default React.memo(CustomHandsontable);

I rendered checkboxes in the row headers instead of numbers. When a checkbox is selected, the React state changes, which causes the CustomHandsontable component to re-render. During re-rendering, I’m getting warnings like:

[Violation] ‘message’ handler took ~500ms
[Violation] Forced reflow while executing JavaScript took ms
[Violation] ‘change’ handler took ~600ms

I’m handling state updates from different Handsontable hooks (like afterBeginEdit, etc.) where I change the state to render something. But whenever the component re-renders due to these updates, I see these warnings, and it takes noticeable time for Handsontable to re-render. It also feels like the thread is getting blocked for 1–2 seconds.

@jaseelkaderi.officia

Please use StackBlitz or CodeSandbox to share the demo.

@adrian.szymanski Here’s the sandbox link https://codesandbox.io/p/sandbox/sad-aryabhata-5dym5z

Hi @jaseelkaderi.officia

Thank you for the demo. I checked it and I can’t observe any significant performance issues. I also tested the situation described in the comments with rapid checkbox checking and unchecking, but it also works fine. Can you please share the exact steps on how to reproduce the problem?

Thanks for checking. In my demo code, the issue is not getting reproduced consistently. However, in my project, while re-rendering Handsontable, the Performance panel shows a forced reflow happening inside Handsontable, which takes a few milliseconds (screenshot attached).

Is this expected behavior for Handsontable while re-rendering?

@jaseelkaderi.officia

Yes, this is expected behavior due to the current architecture.