Skip to content

Commit fd3ca76

Browse files
committed
feat: add a new hook useLocalStorage
1 parent 022a1ce commit fd3ca76

File tree

5 files changed

+105
-0
lines changed

5 files changed

+105
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { useRequest } from '@mints/hooks';
3737
- [useOutsideClick](./docs/use-outside-click.md)
3838
- [useDebounce](./docs/use-debounce.md)
3939
- [useToggle](./docs/use-toggle.md)
40+
- [useLocalStorage](./docs/use-localstorage.md)
4041

4142
## 🌐 LICENSE
4243

__test__/use-localstorage.test.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { renderHook, act } from '@testing-library/react';
2+
3+
import { useLocalStorage } from '../src';
4+
5+
describe('useLocalStorage', () => {
6+
beforeEach(() => {
7+
localStorage.clear();
8+
});
9+
10+
test('should initialize with the value from localStorage', () => {
11+
localStorage.setItem('key', JSON.stringify('stored value'));
12+
13+
const { result } = renderHook(() =>
14+
useLocalStorage('key', 'default value'),
15+
);
16+
17+
expect(result.current[0]).toBe('stored value');
18+
});
19+
20+
test('should initialize with the default value if localStorage is empty', () => {
21+
const { result } = renderHook(() =>
22+
useLocalStorage('key', 'default value'),
23+
);
24+
25+
expect(result.current[0]).toBe('default value');
26+
});
27+
28+
test('should update localStorage when the value changes', () => {
29+
const { result } = renderHook(() =>
30+
useLocalStorage('key', 'default value'),
31+
);
32+
33+
act(() => {
34+
result.current[1]('new value');
35+
});
36+
37+
expect(localStorage.getItem('key')).toBe(JSON.stringify('new value'));
38+
expect(result.current[0]).toBe('new value');
39+
});
40+
41+
test('should initialize with the default value if localStorage is not available', () => {
42+
jest.spyOn(window, 'localStorage', 'get').mockImplementation(() => {
43+
throw new Error('localStorage is not available');
44+
});
45+
46+
const { result } = renderHook(() =>
47+
useLocalStorage('key', 'default value'),
48+
);
49+
50+
expect(result.current[0]).toBe('default value');
51+
});
52+
});

docs/use-localstorage.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# useLocalStorage
2+
3+
> A Hook that store into localStorage..
4+
5+
## Usage
6+
7+
```javascript
8+
import { useState } from 'react';
9+
import { useLocalStorage } from '@mints/hooks';
10+
11+
const Example = () => {
12+
const [value, setValue] = useLocalStorage('key', 0);
13+
14+
return (
15+
<div>
16+
<span>{value}</span>
17+
<span onClick={() => setValue(value + 1)}>Count</span>
18+
<span onClick={() => setValue(0)}>Clear</span>
19+
</div>
20+
);
21+
};
22+
```
23+
24+
## API
25+
26+
```typescript
27+
useLocalStorage = <T>(key: string, initialValue: T): [string, (value: T): void]
28+
```

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './use-auto-refresh';
22
export * from './use-debounce';
3+
export * from './use-localstorage';
34
export * from './use-outside-click';
45
export * from './use-request';
56
export * from './use-toggle';

src/use-localstorage.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useState } from 'react';
2+
3+
export const useLocalStorage = <T>(key: string, initialValue: T) => {
4+
const [storedValue, setStoredValue] = useState(() => {
5+
try {
6+
const item = localStorage.getItem(key);
7+
return item ? JSON.parse(item) : initialValue;
8+
} catch (error) {
9+
return initialValue;
10+
}
11+
});
12+
13+
const setValue = (value: T) => {
14+
try {
15+
const valueToStore =
16+
value instanceof Function ? value(storedValue) : value;
17+
setStoredValue(valueToStore);
18+
localStorage.setItem(key, JSON.stringify(valueToStore));
19+
} catch (error) {}
20+
};
21+
22+
return [storedValue, setValue];
23+
};

0 commit comments

Comments
 (0)