question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

form.reset method call produces memory leak

See original GitHub issue

Describe the bug I have a form that creates entity with 35 fields (some of them are conditional). I added next code to add ability to edit entity:

const Form = ({ entityFromProp }) => {
  const { reset } = useForm();
  ...
  React.useEffect(() => {
    if (entityFromProp) reset(entityFromProp)
    else reset({})
  }, [entityFromProp])
  ...
  // render form
}

And after couple of reset calls I noticed significant performance issue (browser window hangs for some time). I think the root of the problem is MutationObserver usage. Seems like form.reset call creates new observers but does not disconnect old ones.

I think it makes sense to create only one MutationObserver instance at all or at least per useForm hook to reduce unnecessary browser work even if the leak itself will be fixed.

To Reproduce Steps to reproduce the behavior (I can show problem only in local environment because it requires some small source code tweaks):

  1. Bootstrap create-react-app project and add react-hook-form dependency.
  2. Update App.js
import React from 'react';
import { useForm } from 'react-hook-form';

const App = () => {
  const [index, setIndex] = React.useState(0);
  const { register, reset, handleSubmit } = useForm();
  const submit = () => {
    reset({});
  }
  return (
    <>
      <button onClick={() => setIndex(i => i + 1)}>1 / 2 fields</button>
      <br />
      <form onSubmit={handleSubmit(submit)}>
        <input ref={register} name='test' />
        {index % 2 === 0 && <input ref={register} name='test' />}
        <button>Reset</button>
      </form>
    </>
  );
}

export default App;

  1. Go to /node_modules/react-hook-form/dist/index.esm.js and update onDomRemove method declaration (changes are highlighted in screenshot):
Screenshot 2020-08-21 at 03 29 25
setInterval(() => {
    console.log(observers.size);
}, 1000);

const observers = new Set();
function onDomRemove(element, onDetachCallback) {
    const observer = new MutationObserver(() => {
        if (isDetached(element)) {
            observers.delete(observer);
            observer.disconnect();
            onDetachCallback();
        }
    });
    observers.add(observer);
    observer.observe(window.document, {
        childList: true,
        subtree: true,
    });
    return {
        ...observer,
        disconnect: () => {
            observers.delete(observer);
            observer.disconnect()
        }
    };
}
  1. Run project and click on Reset button
  2. Open browser console and observe that counter of active (not disconnected) observers increases: condition

Expected behavior Count of active observers should be equal to count of the fields on the screen.

Codesandbox link (Required) Include a codesandbox will help us to investigate the issue quicker.

https://codesandbox.io/s/react-hook-form-useform-template-forked-kl26f

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
bluebill1049commented, Aug 21, 2020

I am working on a better solution, I will tag you once I have it in place, thanks for picking out this bug. much appreciated.

1reaction
maxsbeltcommented, Aug 21, 2020

@bluebill1049 react-hook-form@6.5.0-beta.1 works really well. Thanks for the quick response 👍

Read more comments on GitHub >

github_iconTop Results From Across the Web

ObjectOutputStream is causing memory leak and reset ...
You don't need to call reset() on the input stream. ... This method only tells you whether you have ever connected this socket....
Read more >
4 Types of Memory Leaks in JavaScript and How to Get Rid Of ...
In this article we will explore common types of memory leaks in client-side JavaScript code. We will also learn how to use the...
Read more >
The 10 Most Common JavaScript Issues Developers Face
Memory Leak Example 1: Dangling References to Defunct Objects. Consider the following code: var theThing = null; var replaceThing = function () ...
Read more >
Memory Leaking Scenarios - Go 101
Kind-of Memory Leaking Caused by Not Resetting Pointers in Lost Slice Elements. In the following code, after the h function is called, the...
Read more >
Operating Lambda: Debugging configurations – Part 2
For example, the following code creates a memory leak between invocations. The Lambda function consumes additional memory with each ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found