Pan/zoom previously drove a full Canvas re-render on every mousemove via setPan() — at 30 LANs that's ~1000 SVG paths and div cards re-evaluating 60 times a second while you drag. The browser screamed. Three fixes, one surgical pass: 1. Pan drag writes the translate/scale transform directly to the pan-layer DOM ref inside requestAnimationFrame; setPan is deferred to mouseup. Grid pattern attributes (x/y/width/height) get the same treatment so the backdrop stays glued to the canvas content. Wheel zoom, resetPan, and zoomBy also sync refs + fire a write so React-driven changes land in one frame. 2. Edge rendering swaps the nodes.find() inside .map() for a Map<id, node> built once per render — O(E) instead of O(E·N). NetBox + NodeCard are now wrapped in React.memo; Canvas hoists the setSelection closures into useCallback so memo can actually short-circuit instead of seeing a fresh prop every render. 3. Drag-a-single-node still mutates state and re-renders, but now only the moved node rerenders — the other 89 skip via memo. Everything that reads panRef.current (toWorld, context menu, drop targeting) still sees the live value during drag because we mutate the ref synchronously on each mousemove; only React state is lazy.
React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Oxc
- @vitejs/plugin-react-swc uses SWC
React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.
Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])