Skip to content

Latest commit

 

History

History
112 lines (86 loc) · 3.78 KB

File metadata and controls

112 lines (86 loc) · 3.78 KB

Integration with React

The HyperFormula API is identical in a React app and in plain JavaScript. What changes is where the engine lives in a component tree and how its lifecycle maps to React hooks.

Install with npm install hyperformula. For other options, see the client-side installation section.

Basic usage

Hold the HyperFormula instance in a useRef so it survives re-renders. Initialize it inside useEffect and release it in the cleanup function. Use useState to toggle between raw formulas and computed values.

import { useEffect, useRef, useState } from 'react';
import { HyperFormula, CellValue } from 'hyperformula';

export function SpreadsheetComponent() {
  const hfRef = useRef<HyperFormula | null>(null);
  const [values, setValues] = useState<CellValue[][]>([]);

  useEffect(() => {
    const hf = HyperFormula.buildFromArray(
      [
        [1, 2, '=A1+B1'],
        // your data rows go here
      ],
      {
        licenseKey: 'gpl-v3',
        // more configuration options go here
      }
    );
    hfRef.current = hf;

    return () => {
      hf.destroy();
      hfRef.current = null;
    };
  }, []);

  function runCalculations() {
    if (!hfRef.current) return;
    setValues(hfRef.current.getSheetValues(0));
  }

  function reset() {
    setValues([]);
  }

  return (
    <>
      <button onClick={runCalculations}>Run calculations</button>
      <button onClick={reset}>Reset</button>
      {values.length > 0 && (
        <table>
          <tbody>
            {values.map((row, r) => (
              <tr key={r}>
                {row.map((cell, c) => (
                  <td key={c}>{String(cell ?? '')}</td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </>
  );
}

If you use JavaScript instead of TypeScript, drop the type annotations — the rest of the pattern is unchanged.

Notes

React.StrictMode double invocation

In development, React 18 runs effects twice (mount → unmount → mount) to surface cleanup bugs. The pattern above is correct for StrictMode because destroy() runs before the re-mount creates a new instance, so no work leaks between the two lifecycles. Do not switch to a module-scoped singleton as a workaround — it will break StrictMode semantics.

Server-side rendering (Next.js)

HyperFormula depends on browser-only APIs. Mark SpreadsheetComponent.tsx with 'use client', then load it lazily from a server page component using dynamic(..., { ssr: false }):

// app/spreadsheet/SpreadsheetComponent.tsx
'use client';
// ... component definition as above
// app/spreadsheet/page.tsx  ← server component, no 'use client'
import dynamic from 'next/dynamic';

const SpreadsheetComponent = dynamic(
  () => import('./SpreadsheetComponent').then((m) => m.SpreadsheetComponent),
  { ssr: false }
);

export default function Page() {
  return <SpreadsheetComponent />;
}

Putting 'use client' on page.tsx itself would make the entire page a client component — the point is to keep the page server-rendered and only hydrate the spreadsheet widget on the client. In the Pages Router, the same dynamic(..., { ssr: false }) pattern works without 'use client'.

Next steps

Demo

For a more advanced example, check out the React demo on Stackblitz.