Skip to content

Commit

Permalink
feat: add useError hook
Browse files Browse the repository at this point in the history
  • Loading branch information
ayush987goyal committed Jan 16, 2020
1 parent 7c56ed2 commit 65f3644
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
34 changes: 34 additions & 0 deletions docs/useError.md
Original file line number Diff line number Diff line change
@@ -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`
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
19 changes: 19 additions & 0 deletions src/useError.ts
Original file line number Diff line number Diff line change
@@ -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;
46 changes: 46 additions & 0 deletions stories/useError.story.tsx
Original file line number Diff line number Diff line change
@@ -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 changes: 26 additions & 0 deletions tests/useError.test.ts
Original file line number Diff line number Diff line change
@@ -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);
}
});

0 comments on commit 65f3644

Please sign in to comment.