form.reset method call produces memory leak
See original GitHub issueDescribe 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):
- Bootstrap
create-react-app
project and addreact-hook-form
dependency. - 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;
- Go to
/node_modules/react-hook-form/dist/index.esm.js
and updateonDomRemove
method declaration (changes are highlighted in screenshot):

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()
}
};
}
- Run project and click on
Reset
button - Open browser console and observe that counter of active (not disconnected) observers increases:
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:
- Created 3 years ago
- Comments:6 (5 by maintainers)
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.
@bluebill1049
react-hook-form@6.5.0-beta.1
works really well. Thanks for the quick response 👍