Skip to content

Commit 36fa503

Browse files
fix(form-core): Resolve memory leaks for SSR / Devtools (#1866)
* fix: unsubscribe from EventClient event listeners on cleanup * chore: bump devtools-event-client * ci: apply automated fixes and generate docs * Resolve memory leaks for SSR / Devtools * ci: apply automated fixes and generate docs --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent e6e280b commit 36fa503

File tree

4 files changed

+328
-205
lines changed

4 files changed

+328
-205
lines changed

.changeset/honest-beers-carry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/form-core': patch
3+
---
4+
5+
fix(form-core): Resolve memory leaks for SSR / Devtools

packages/form-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"src"
5252
],
5353
"dependencies": {
54-
"@tanstack/devtools-event-client": "^0.3.5",
54+
"@tanstack/devtools-event-client": "^0.4.0",
5555
"@tanstack/pacer-lite": "^0.1.1",
5656
"@tanstack/store": "^0.7.7"
5757
},

packages/form-core/src/FormApi.ts

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,36 +1310,6 @@ export class FormApi<
13101310
this.handleSubmit = this.handleSubmit.bind(this)
13111311

13121312
this.update(opts || {})
1313-
1314-
// devtool broadcasts
1315-
this.store.subscribe(() => {
1316-
throttleFormState(this)
1317-
})
1318-
1319-
// devtool requests
1320-
formEventClient.on('request-form-state', (e) => {
1321-
if (e.payload.id === this._formId) {
1322-
formEventClient.emit('form-api', {
1323-
id: this._formId,
1324-
state: this.store.state,
1325-
options: this.options,
1326-
})
1327-
}
1328-
})
1329-
1330-
formEventClient.on('request-form-reset', (e) => {
1331-
if (e.payload.id === this._formId) {
1332-
this.reset()
1333-
}
1334-
})
1335-
1336-
formEventClient.on('request-form-force-submit', (e) => {
1337-
if (e.payload.id === this._formId) {
1338-
this._devtoolsSubmissionOverride = true
1339-
this.handleSubmit()
1340-
this._devtoolsSubmissionOverride = false
1341-
}
1342-
})
13431313
}
13441314

13451315
get formId(): string {
@@ -1374,7 +1344,51 @@ export class FormApi<
13741344
mount = () => {
13751345
const cleanupFieldMetaDerived = this.fieldMetaDerived.mount()
13761346
const cleanupStoreDerived = this.store.mount()
1347+
1348+
// devtool broadcasts
1349+
const cleanupDevtoolBroadcast = this.store.subscribe(() => {
1350+
throttleFormState(this)
1351+
})
1352+
1353+
// devtool requests
1354+
const cleanupFormStateListener = formEventClient.on(
1355+
'request-form-state',
1356+
(e) => {
1357+
if (e.payload.id === this._formId) {
1358+
formEventClient.emit('form-api', {
1359+
id: this._formId,
1360+
state: this.store.state,
1361+
options: this.options,
1362+
})
1363+
}
1364+
},
1365+
)
1366+
1367+
const cleanupFormResetListener = formEventClient.on(
1368+
'request-form-reset',
1369+
(e) => {
1370+
if (e.payload.id === this._formId) {
1371+
this.reset()
1372+
}
1373+
},
1374+
)
1375+
1376+
const cleanupFormForceSubmitListener = formEventClient.on(
1377+
'request-form-force-submit',
1378+
(e) => {
1379+
if (e.payload.id === this._formId) {
1380+
this._devtoolsSubmissionOverride = true
1381+
this.handleSubmit()
1382+
this._devtoolsSubmissionOverride = false
1383+
}
1384+
},
1385+
)
1386+
13771387
const cleanup = () => {
1388+
cleanupFormForceSubmitListener()
1389+
cleanupFormResetListener()
1390+
cleanupFormStateListener()
1391+
cleanupDevtoolBroadcast()
13781392
cleanupFieldMetaDerived()
13791393
cleanupStoreDerived()
13801394

0 commit comments

Comments
 (0)