-
Notifications
You must be signed in to change notification settings - Fork 585
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #415 from little-buddy/master
refactor(hook): useWillUnmount impl by useLayoutEffect BREAKING CHANGE: renames useWillUnmount into useUnmount
- Loading branch information
Showing
6 changed files
with
172 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# useUnmount | ||
|
||
A hook that takes in a function to execute right when the component unmounts. | ||
|
||
### Why? 💡 | ||
|
||
- takes care of performing a callback when the component unmounts | ||
|
||
### Basic Usage: | ||
|
||
```jsx harmony | ||
import { Typography } from 'antd'; | ||
import useUnmount from 'beautiful-react-hooks/useUnmount'; | ||
|
||
const ComponentUnmount = () => { | ||
useUnmount(() => { | ||
console.log('Component did unmount'); | ||
}); | ||
|
||
return ( | ||
<DisplayDemo title="useUnmount"> | ||
<Typography.Paragraph>Check the javascript console complete moving from this page</Typography.Paragraph> | ||
</DisplayDemo> | ||
); | ||
}; | ||
|
||
<ComponentUnmount />; | ||
``` | ||
|
||
### Callback setter syntax: | ||
|
||
If the first parameter is omitted, you can use the returned function (a callback setter) to set the useWillUnmount handler. However, you | ||
must immediately invoke the callback setter. | ||
|
||
Important: The callback setter only changes the value of the callback reference and does not trigger a component rerender. Also, avoid | ||
invoking it asynchronously | ||
|
||
```jsx harmony | ||
import { Typography } from 'antd'; | ||
import useUnmount from 'beautiful-react-hooks/useUnmount'; | ||
|
||
const ComponentUnmount = () => { | ||
const onUnmount = useUnmount(); | ||
|
||
onUnmount(() => { | ||
console.log('Component did unmount'); | ||
}); | ||
|
||
return ( | ||
<DisplayDemo title="useUnmount"> | ||
<Typography.Paragraph> | ||
Check the javascript console complete moving from this page | ||
</Typography.Paragraph> | ||
</DisplayDemo> | ||
); | ||
}; | ||
|
||
<ComponentUnmount />; | ||
``` | ||
|
||
#### ✅ Pro tip: | ||
|
||
When using a React function component you should not really think of it in terms of "lifecycle". | ||
|
||
The `useUnmount` hook is indeed intended as a shortcut to `useEffect(() => () => Unmount, [])`. | ||
|
||
To deep understanding `useEffect`, what it is and how it should be properly used, please read | ||
"[A complete guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)" | ||
by [Dan Abramov](https://twitter.com/dan_abramov) | ||
|
||
### Mastering the hook | ||
|
||
#### ✅ When to use | ||
|
||
- When you need to perform a function after the component has mounted | ||
|
||
#### 🛑 When not to use | ||
|
||
- Avoid using this hook asynchronously since it would violate the [rules of hooks](https://reactjs.org/docs/hooks-rules.html) | ||
- If you're using the callback setter, make sure to invoke it immediately instead of asynchronously | ||
|
||
<!-- Types --> | ||
### Types | ||
|
||
```typescript static | ||
import { type GenericFunction } from './shared/types'; | ||
/** | ||
* Returns a callback setter for a callback to be performed when the component did unmount. | ||
*/ | ||
declare const useUnmount: <TCallback extends GenericFunction>(callback?: TCallback | undefined) => import("./shared/types").CallbackSetter<undefined>; | ||
export default useUnmount; | ||
|
||
``` | ||
|
||
<!-- Types:end --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { useEffect, useRef } from "react"; | ||
import isFunction from "./shared/isFunction"; | ||
import { type GenericFunction } from "./shared/types"; | ||
import createHandlerSetter from "./factory/createHandlerSetter"; | ||
|
||
/** | ||
* Returns a callback setter for a callback to be performed when the component did unmount. | ||
*/ | ||
const useUnmount = <TCallback extends GenericFunction>( | ||
callback?: TCallback | ||
) => { | ||
const mountRef = useRef(false); | ||
const [handler, setHandler] = createHandlerSetter<undefined>(callback); | ||
|
||
useEffect(() => { | ||
mountRef.current = true; | ||
|
||
return () => { | ||
if (isFunction(handler?.current) && mountRef.current) { | ||
handler.current(); | ||
} | ||
}; | ||
}, []); | ||
|
||
return setHandler; | ||
}; | ||
|
||
export default useUnmount; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import React from 'react' | ||
import { cleanup as cleanupReact, render } from '@testing-library/react' | ||
import { cleanup as cleanupHooks, renderHook } from '@testing-library/react-hooks' | ||
import useUnmount from '../dist/useUnmount' | ||
import assertHook from './utils/assertHook' | ||
|
||
describe('useUnmount', () => { | ||
beforeEach(() => { | ||
cleanupHooks() | ||
cleanupReact() | ||
}) | ||
|
||
assertHook(useUnmount) | ||
|
||
it('should return a single function', () => { | ||
const { result } = renderHook(() => useUnmount()) | ||
|
||
expect(result.current).to.be.a('function') | ||
}) | ||
|
||
it('the returned function should be a setter for a callback to be performed when component did unmount', () => { | ||
const spy = sinon.spy() | ||
|
||
const TestComponent = () => { | ||
const onUnmount = useUnmount() | ||
|
||
onUnmount(spy) | ||
|
||
return null | ||
} | ||
|
||
const { rerender } = render(<TestComponent />) | ||
|
||
rerender(null) | ||
|
||
expect(spy.called).to.be.true | ||
}) | ||
}) |