Skip to content

Commit 36082c2

Browse files
Added useTitle, useIsOnline hooks
1 parent 161de6e commit 36082c2

File tree

16 files changed

+5755
-5619
lines changed

16 files changed

+5755
-5619
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ docs/node_modules
33
docs/.docusaurus
44
docs/build
55
docs/src/hooks
6+
docs/blog
67
dist
78
example
8-
test
9+
test

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ yarn add react-use-custom-hooks
1212
# Usage
1313

1414
```ts
15-
import { useSafeState } from 'react-use-custom-hooks';
15+
import { useDebounce } from 'react-use-custom-hooks';
1616
```
1717

18-
# Demo
18+
# Documentation and demo
1919

2020
https://react-use-custom-hooks.vercel.app/

docs/docs/useIsOnline.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# useIsOnline
2+
3+
A hook for detecting network status of the user. This hook will return a boolean value indicating whether the user is online or not. The value will be automatically updated when the user's network status changes.
4+
5+
<pre>{`import {useIsOnline} from 'react-use-custom-hooks';`}</pre>
6+
7+
:::caution
8+
The hook works based on value of `navigator.onLine` property, so this hook returns `true` does not always mean the user connected to the internet, it can also just a connection to some network.
9+
10+
If the browser doesn't support `navigator.onLine`, the hook will return `false/undefined`.
11+
12+
Early versions of Chrome and Safari always reported "true" for navigator.onLine
13+
14+
Desktop Firefox responds to the status of its "Work Offline" mode. If not in that mode, `navigator.onLine` is always true, regardless of the actual network connectivity status. See [ firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=654579) for details.
15+
16+
:::
17+
18+
### Usage example
19+
20+
```typescript
21+
const isOnline: boolean = useIsOnline();
22+
```
23+
24+
### Playground
25+
26+
Try disconnecting and then connecting your network and see the value changes.
27+
28+
```jsx live
29+
function IsOnlineExample(props) {
30+
const isOnline = useIsOnline();
31+
return <>User is online: {isOnline.toString()}</>;
32+
}
33+
```
34+
35+
### API
36+
37+
```typescript
38+
export function useIsOnline(): Boolean;
39+
```

docs/docs/useSafeState.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# useSafeState
22

3+
:::caution This hook will be deprecated soon
4+
5+
The warning from react when you set state on unmounted component will be removed from React 18 onwards since there is no actual memory leak in case of promises and the warning is misleading in those scenarios. Also future version of react offer a feature that lets you preserve DOM and state even when the component is not visible, but disconnect its effects. That might not work will with the implementation of this hook.
6+
7+
See detailed discussion here - https://github.com/reactwg/react-18/discussions/82
8+
9+
:::
10+
311
A memory safe version of react's `useState` hook. In react, on way memory leak occurs when `setState` operation performed on an unmounted component and it happens mostly with asynchronous operation like AJAX calls.
412

513
For example, if the user initiated an AJAX call and navigated away from tha page before the call is returned, the component will get unmounted and when the api call is fulfilled, the `setState` will be performed on the unmounted component causing a memory leak.

docs/docs/useTitle.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# useTitle
2+
3+
A hook to manage title value of document.
4+
5+
<pre>{`import {useTitle} from 'react-use-custom-hooks';`}</pre>
6+
7+
### Usage example
8+
9+
```typescript
10+
useTitle('My title');
11+
```
12+
13+
### Playground
14+
15+
You can pass static value or computed value, state or prop to `useTitle` hook. The title of the document will get's updated whenever the value changes. Also you can restore the previous title if the component using this hook unmounts. Pass `restoreOnUnmount` value `true` in `options` object to configure the behavior.
16+
17+
```jsx live
18+
function TitleExample(props) {
19+
const [title, setTitle] = useState('My Title!');
20+
useTitle(title);
21+
return (
22+
<>
23+
<input
24+
type="text"
25+
value={title}
26+
onChange={e => setTitle(e.target.value)}
27+
/>
28+
</>
29+
);
30+
}
31+
```
32+
33+
### API
34+
35+
```typescript
36+
interface Options {
37+
restoreOnUnmount?: boolean;
38+
}
39+
40+
export function useTitle(
41+
title: string,
42+
options: Options = DEFAULT_OPTIONS
43+
): void;
44+
```
45+
46+
#### Options
47+
48+
| Property | Description | Type | Default |
49+
| ---------------- | ---------------------------------------------- | --------- | ------- |
50+
| restoreOnUnmount | Indicate to restore the title value on unmount | `boolean` | false |

docs/docusaurus.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ const config = {
5151
playgroundPosition: 'bottom',
5252
},
5353
navbar: {
54-
// title: 'Hooks studio',
54+
title: 'React Use Custom Hooks',
5555
logo: {
56-
alt: 'Hooks studio logo',
57-
src: 'img/h2.svg',
56+
alt: 'Home page of react use custom hooks',
57+
src: 'img/logo.png',
5858
},
5959
items: [
6060
// {

docs/src/components/HookDetails.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default function HookDetails() {
1818
Usage
1919
</h3>
2020
<pre>
21-
{`import {useSafeState} from 'react-use-custom-hooks';`}
21+
{`import {useDebounce} from 'react-use-custom-hooks';`}
2222
</pre>
2323
</div>
2424
</section>

docs/src/pages/index.module.css

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
background: rgb(255, 45, 116);
2727
color: white !important;
2828
}
29-
/* .buttons a:hover {
30-
transform: translate3d(0px, -2px, 0px);
31-
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px 0px;
32-
transition: all 150ms linear 0s;
33-
} */
29+
.buttons a:hover {
30+
background: #e24053;
31+
}

docs/src/theme/ReactLiveScope/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11

22
import React from 'react';
3-
import { useDebounce, useSafeState, useIsMounted, usePrevious, useLegacyState } from "react-use-custom-hooks";
3+
import { useDebounce, useSafeState, useIsMounted, usePrevious, useLegacyState, useTitle, useIsOnline } from "react-use-custom-hooks";
44

55
// Add react-live imports you need here
66
const ReactLiveScope = {
77
React,
88
...React,
9-
useDebounce, useSafeState, useIsMounted, usePrevious, useLegacyState
9+
useDebounce, useSafeState, useIsMounted, usePrevious, useLegacyState, useTitle, useIsOnline
1010
};
1111

1212
export default ReactLiveScope;

docs/static/img/favicon.ico

14.9 KB
Binary file not shown.

docs/static/img/h2.svg

Lines changed: 0 additions & 74 deletions
This file was deleted.

docs/static/img/logo.png

12.6 KB
Loading

src/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,15 @@ import { useSafeState } from './useSafeState';
33
import { useIsMounted } from './useIsMounted';
44
import { usePrevious } from './usePrevious';
55
import { useLegacyState } from './useLegacyState';
6+
import { useTitle } from './useTitle';
7+
import { useIsOnline } from './useIsOnline';
68

7-
export { useDebounce, useSafeState, useIsMounted, usePrevious, useLegacyState };
9+
export {
10+
useDebounce,
11+
useSafeState,
12+
useIsMounted,
13+
usePrevious,
14+
useLegacyState,
15+
useTitle,
16+
useIsOnline,
17+
};

src/useIsOnline.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useCallback } from 'react';
2+
import { useState } from 'react';
3+
import { useEffect } from 'react';
4+
5+
export function useIsOnline(): Boolean {
6+
const isNavigatorOnLineDefined: boolean =
7+
typeof window.navigator.onLine === 'boolean';
8+
const [isOnline, setIsOnline] = useState<boolean>(window.navigator.onLine);
9+
10+
const onStatusChange = useCallback(
11+
() => setIsOnline(window.navigator.onLine),
12+
[]
13+
);
14+
15+
useEffect(() => {
16+
if (!isNavigatorOnLineDefined) {
17+
return;
18+
}
19+
window.addEventListener('online', onStatusChange);
20+
window.addEventListener('offline', onStatusChange);
21+
22+
return () => {
23+
window.removeEventListener('online', onStatusChange);
24+
window.removeEventListener('offline', onStatusChange);
25+
};
26+
}, []);
27+
28+
return isOnline;
29+
}

src/useTitle.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useEffect, useRef } from 'react';
2+
3+
interface Options {
4+
restoreOnUnmount?: boolean;
5+
}
6+
7+
const DEFAULT_OPTIONS: Options = {
8+
restoreOnUnmount: false,
9+
};
10+
11+
export function useTitle(
12+
title: string,
13+
options: Options = DEFAULT_OPTIONS
14+
): void {
15+
const isDocumentDefined = typeof document !== 'undefined';
16+
const originalTitle = useRef(isDocumentDefined ? document.title : '');
17+
18+
useEffect(() => {
19+
if (!isDocumentDefined) return;
20+
if (document.title !== title) document.title = title;
21+
return () => {
22+
if (options?.restoreOnUnmount) document.title = originalTitle.current;
23+
};
24+
}, [title]);
25+
}

0 commit comments

Comments
 (0)