-
Notifications
You must be signed in to change notification settings - Fork 233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unmount doesn't seem to be firing useEffect cleanup functions #847
Comments
I imagine it’s the fake timers getting in the way. Try without that line and see if it works (I’m unable to test it myself at the moment) |
I have the same problem without any fake timers. I have an RxJS observable which I |
I'm also having this issue, I call a function on the window in my effect cleanup but I can't asset that it's being called as the clean up function never get's called when unmounting. Is anyone looking into this? Thanks. |
Hi @dahliacreative, Noone is currently looking into this but we have tests that ensure the effects are cleaned up, so it's unlikely to be an issue with this library or react itself (I cannot stress how much of our functionality is just calling react to do it's thing) and much more likely to be in your code. A common issue I see is that the work in the cleanup is actually async and has not run in between the If you want help diagnosing the issue, I suggest sharing some code here/a new "Question" issue/discord, or putting together a small reproduction repo if you cannot share your actual code with us. |
Have same issue - not firing useEffect cleanup on unmount. Here is the code snippet I am using:
Tried wrapping unmount around act, but unmount already does that - so that's not it. Edit: Caching a reference to the useEffect's cleanup function
Then finally calling this reference on unmount
|
try skiping one thread cycle before expecting:
|
This did not work for me @vzaidman but what did work @kmarple1 was the following: Component import { useEffect } from 'react'
const Component = () => {
useEffect(async () => {
console.log('renders')
return () => {
console.log('cleanup')
}
}, [url])
return <div/>
}
export default Component it('unmounts', async () => {
console.log = jest.fn()
let cleanupFuncPromise
jest.spyOn(React, 'useEffect').mockImplementationOnce(func => cleanupFuncPromise = func())
const subject = await render(<Component/>)
await subject.unmount()
const cleanUpFunction = await cleanupFuncPromise
cleanUpFunction()
expect(console.log).toHaveBeenCalledWith('cleanup)
}) |
Any updates on this? |
Hi @Fawwad-Khan No update from my end. If you want to share some code (or ideally a reproduction repo) I'm may be able to spot something obvious, but I don't have a lot of time for deep debugging on issues like this (I'll reiterate that it's unlikely to be this library causing the issue here). Also, @ignatospadov, I've just noticed that your usage of const Component = () => {
useEffect(() => {
const run = async () => {
console.log('renders')
}
run()
return () => {
console.log('cleanup')
}
}, [url])
return <div/>
} Hope that helps. |
I cant really share the code as the organization I work at doesnt let me. Im unsetting the UIState on unmount but im still getting the "something" value after unmount in my test.
|
Hello, if this can be of any help, here is a reproduction code: // src/useMount.ts
import { useEffect, useState } from 'react'
export function useMount() {
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
return () => {
setMounted(false)
}
}, [])
return mounted
} // tests/unit/useMount.test.ts
import { renderHook } from '@testing-library/react'
import { useMount } from '../../src/useMount'
describe('useMount', () => {
it('should be mounted', () => {
const { result } = renderHook(useMount)
expect(result.current).toBe(true)
})
it('should not be mounted after unmount', () => {
const { result, unmount } = renderHook(useMount)
unmount()
expect(result.current).toBe(false)
})
}) Dependencies: "@testing-library/dom": "^9.3.1",
"@testing-library/react": "^14.0.0",
"@types/jest": "^29.5.2",
"@types/react": "^18.2.13",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-jest": "^29.1.0",
"typescript": "^5.1.3" This code is hosted here: https://github.com/saramorillon/hooks/tree/reproduction-847 |
Here is how this hook is implemented on the usehooks-ts library. I hope this example can provide some helpful insights! 👍 |
Anyone found the solution, here is my code where issue is happening. React.useEffect(() => {
emitter.on(MY_EVENT,callback);
return () => {
console.log('unsubscribing'); // <<--- Its not getting console logged.
emitter.off(MY_EVENT, callback);
};
}, []); it.only('should add and remove event listeners', () => {
const { unmount } = render(<Component {...defaultProps} />);
expect(emitter.on).toHaveBeenCalledTimes(1);
expect(observers[MY_EVENT).toBeDefined();
unmount();
expect(emitter.off).toHaveBeenCalledTimes(1);
expect(observers[MY_EVENT]).toBeUndefined();
});
}); expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
23 |
24 | unmount();
> 25 | expect(emitter.off).toHaveBeenCalledTimes(1);
| ^
26 | expect(observers[MY_EVENT]).toBeUndefined(); |
@bhushanlaware it looks like you are rendering with As a general reminder to others coming into this issue, if you are importing Also a general suspicion that fake timers, unhandled async or mocked |
Would it help to use act?
|
react-hooks-testing-library
version: 8.0.0react
version: ^17.0.2react-dom
version (if applicable): ^17.0.2react-test-renderer
version (if applicable): n/anode
version: v14.17.6npm
(oryarn
) version: 6.14.15Relevant code or config:
The component I'm testing:
The test itself:
What you did:
I'm attempting to test that the useEffect cleanup function in my hook fires correctly.
What happened:
While it works properly when running normally, I can't get unmount() to fire it.
Reproduction:
The above example reproduces the problem.
Problem description:
Unmount doesn't seem to be properly cleanup up useEffects.
The text was updated successfully, but these errors were encountered: