From fbd8be316045939c55f2d2013a384eddd0e436c7 Mon Sep 17 00:00:00 2001 From: Szymon Dolnik Date: Wed, 3 Jun 2026 13:47:46 +0200 Subject: [PATCH 1/2] docs: rewrite Vue integration guide around markRaw pattern - Replace SpreadsheetProvider class with markRaw as the primary pattern - Remove Updating cells section; mutation hint moved inline after the example - Reframe SSR section: HyperFormula is SSR-safe by default, ClientOnly is optional - Add TypeScript tip with JS note - Tighten prose throughout --- docs/guide/integration-with-vue.md | 82 +++++++++++------------------- 1 file changed, 31 insertions(+), 51 deletions(-) diff --git a/docs/guide/integration-with-vue.md b/docs/guide/integration-with-vue.md index 087a84f61..61c229ca7 100644 --- a/docs/guide/integration-with-vue.md +++ b/docs/guide/integration-with-vue.md @@ -4,67 +4,47 @@ The HyperFormula API is identical in a Vue 3 app and in plain JavaScript. This g Install with `npm install hyperformula`. For other options, see the [client-side installation](client-side-installation.md) section. -## Basic usage - -Wrap the HyperFormula instance inside a plain class so it stays outside Vue's reactivity system (see [Troubleshooting](#vue-reactivity-issues) below for why this matters). Hold derived data in `ref` so the template updates when you reassign the ref's `.value`. +::: tip TypeScript +All examples use TypeScript. Remove the type annotations to use plain JavaScript. +::: -```typescript -// spreadsheet-provider.ts -import { HyperFormula, type CellValue } from 'hyperformula'; - -export class SpreadsheetProvider { - private hf: HyperFormula; - - constructor(data: (string | number | null)[][]) { - this.hf = HyperFormula.buildFromArray(data, { - licenseKey: 'gpl-v3', - // more configuration options go here - }); - } - - getCalculatedValues(): CellValue[][] { - return this.hf.getSheetValues(0); - } - - getRawFormulas(): (string | number | null)[][] { - return this.hf.getSheetSerialized(0) as (string | number | null)[][]; - } - - destroy() { - this.hf.destroy(); - } -} -``` +## Basic usage -Use the class from a component with ` ``` -The class keeps the HyperFormula instance as a private field, so Vue's reactivity Proxy never reaches it. This is the same pattern used in the [Vue 3 demo](#demo). +`hf` is marked raw so Vue never proxies it — `values` is the only reactive piece. To mutate data, call any HyperFormula method (e.g. `setCellContents`) then reassign `values.value` to trigger a re-render. See [Basic operations](basic-operations.md) for the full mutation API. ## Server-side rendering (Nuxt) -The class above is already SSR-safe — HyperFormula has no browser-only API dependency. To skip the (otherwise wasted) server-side instantiation in Nuxt, wrap the component with ``. +HyperFormula has no browser-only API dependency. To skip server-side computation, wrap the component with ``. ## Troubleshooting @@ -89,16 +69,16 @@ If you encounter an error like Uncaught TypeError: Cannot read properties of undefined (reading 'licenseKeyValidityState') ``` -it means that Vue's reactivity system tried to deeply observe the HyperFormula instance. Vue wraps reactive objects in a `Proxy` that intercepts every property access; when that proxy reaches a non-trivial instance with its own internal state, identity checks and lazy-initialized maps break. The fix is to opt the instance out of reactivity with Vue's [`markRaw`](https://vuejs.org/api/reactivity-advanced.html#markraw): +it means that Vue's reactivity system tried to deeply observe the HyperFormula instance. Vue wraps reactive objects in a `Proxy` that intercepts every property access; when that proxy reaches a non-trivial instance with its own internal state, identity checks and lazy-initialized maps break. The fix is to opt the instance out of reactivity with [`markRaw`](https://vuejs.org/api/reactivity-advanced.html#markraw): ```typescript -import { markRaw } from 'vue'; -import { HyperFormula } from 'hyperformula'; +import { markRaw } from "vue"; +import { HyperFormula } from "hyperformula"; -const hfInstance = markRaw( +const hf = markRaw( HyperFormula.buildEmpty({ - licenseKey: 'gpl-v3', - }) + licenseKey: "gpl-v3", + }), ); ``` From 650eb19f0d7ff8f115d2613969f98ef6b360e76e Mon Sep 17 00:00:00 2001 From: Szymon Dolnik Date: Wed, 3 Jun 2026 13:53:48 +0200 Subject: [PATCH 2/2] docs: add TypeScript tip to React integration guide --- docs/guide/integration-with-react.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/guide/integration-with-react.md b/docs/guide/integration-with-react.md index 2a0820139..f5782b9b3 100644 --- a/docs/guide/integration-with-react.md +++ b/docs/guide/integration-with-react.md @@ -4,6 +4,10 @@ The HyperFormula API is identical in a React app and in plain JavaScript. This g Install with `npm install hyperformula`. For other options, see the [client-side installation](client-side-installation.md) section. +::: tip TypeScript +All examples use TypeScript. Remove the type annotations to use plain JavaScript. +::: + ## 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. @@ -67,8 +71,6 @@ export default function SpreadsheetComponent() { } ``` -If you use JavaScript instead of TypeScript, drop the type annotations — the rest of the pattern is unchanged. - ## `React.StrictMode` double invocation In development, React 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.