Merge pull request #902 from ayush987goyal/pr/use-error

feat: add useError hook
This commit is contained in:
Vadim Dalecky 2020-01-16 10:28:08 -08:00 committed by GitHub
commit 51d53b76c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 0 deletions

View File

@ -97,6 +97,7 @@
- [`useCookie`](./docs/useCookie.md) — provides way to read, update and delete a cookie. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usecookie--demo)
- [`useCopyToClipboard`](./docs/useCopyToClipboard.md) — copies text to clipboard.
- [`useDebounce`](./docs/useDebounce.md) — debounces a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usedebounce--demo)
- [`useError`](./docs/useError.md) — error dispatcher. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-useerror--demo)
- [`useFavicon`](./docs/useFavicon.md) — sets favicon of the page.
- [`useLocalStorage`](./docs/useLocalStorage.md) — manages a value in `localStorage`.
- [`useLockBodyScroll`](./docs/useLockBodyScroll.md) — lock scrolling of the body element.

34
docs/useError.md Normal file
View File

@ -0,0 +1,34 @@
# `useError`
React side-effect hook that returns an error dispatcher.
## Usage
```jsx
import { useError } from 'react-use';
const Demo = () => {
const dispatchError = useError();
const clickHandler = () => {
dispatchError(new Error('Some error!'));
};
return <button onClick={clickHandler}>Click me to throw</button>;
};
// In parent app
const App = () => (
<ErrorBoundary>
<Demo />
</ErrorBoundary>
);
```
## Reference
```js
const dispatchError = useError();
```
- `dispatchError` &mdash; Callback of type `(err: Error) => void`

View File

@ -21,6 +21,7 @@ export { default as useDropArea } from './useDropArea';
export { default as useEffectOnce } from './useEffectOnce';
export { default as useEnsuredForwardedRef, ensuredForwardRef } from './useEnsuredForwardedRef';
export { default as useEvent } from './useEvent';
export { default as useError } from './useError';
export { default as useFavicon } from './useFavicon';
export { default as useFullscreen } from './useFullscreen';
export { default as useGeolocation } from './useGeolocation';

19
src/useError.ts Normal file
View File

@ -0,0 +1,19 @@
import { useState, useEffect, useCallback } from 'react';
const useError = (): ((err: Error) => void) => {
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
if (error) {
throw error;
}
}, [error]);
const dispatchError = useCallback((err: Error) => {
setError(err);
}, []);
return dispatchError;
};
export default useError;

View File

@ -0,0 +1,46 @@
import { storiesOf } from '@storybook/react';
import React from 'react';
import { useError } from '../src';
import ShowDocs from './util/ShowDocs';
class ErrorBoundary extends React.Component<{}, { hasError: boolean }> {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return (
<div>
<h1>Something went wrong.</h1>
<button onClick={() => this.setState({ hasError: false })}>Retry</button>
</div>
);
}
return this.props.children;
}
}
const Demo = () => {
const dispatchError = useError();
const clickHandler = () => {
dispatchError(new Error('Some error!'));
};
return <button onClick={clickHandler}>Click me to throw</button>;
};
storiesOf('Side effects|useError', module)
.add('Docs', () => <ShowDocs md={require('../docs/useLocalStorage.md')} />)
.add('Demo', () => (
<ErrorBoundary>
<Demo />
</ErrorBoundary>
));

26
tests/useError.test.ts Normal file
View File

@ -0,0 +1,26 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { useError } from '../src';
const setup = () => renderHook(() => useError());
beforeEach(() => {
jest.spyOn(console, 'error').mockImplementation(() => {});
});
afterEach(() => {
jest.clearAllMocks();
});
it('should throw an error on error dispatch', () => {
const errorStr = 'some_error';
try {
const { result } = setup();
act(() => {
result.current(new Error(errorStr));
});
} catch (err) {
expect(err.message).toEqual(errorStr);
}
});