Skip to content

Commit

Permalink
Merge pull request alibaba#770 from alibaba/refactor/use-storage-state
Browse files Browse the repository at this point in the history
refactor: useStorageState -> createUseStorageState
  • Loading branch information
brickspert authored Dec 16, 2020
2 parents 589d31a + 62ded21 commit 712b04b
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 99 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { act, renderHook } from '@testing-library/react-hooks';
import useStorageState, { IFuncUpdater } from '../index';
import { IFuncUpdater, createUseStorageState } from '../index';

class TestStorage implements Storage {
[name: string]: any;
Expand Down Expand Up @@ -48,10 +48,11 @@ interface StorageStateProps<T> {
describe('useStorageState', () => {
const setUp = <T>(props: StorageStateProps<T>) => {
const storage = new TestStorage();
const useStorageState = createUseStorageState(storage);

return renderHook(
({ key, defaultValue }: StorageStateProps<T>) => {
const [state, setState] = useStorageState(storage, key, defaultValue);
const [state, setState] = useStorageState(key, defaultValue);

return { state, setState };
},
Expand All @@ -62,7 +63,7 @@ describe('useStorageState', () => {
};

it('should be defined', () => {
expect(useStorageState);
expect(createUseStorageState);
});

it('should get defaultValue for a given key', () => {
Expand Down
71 changes: 71 additions & 0 deletions packages/hooks/src/createUseStorageState/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useState, useCallback } from 'react';
import useUpdateEffect from '../useUpdateEffect';

export interface IFuncUpdater<T> {
(previousState?: T): T;
}

export interface IFuncStorage {
(): Storage;
}

export type StorageStateResult<T> = [T | undefined, (value?: T | IFuncUpdater<T>) => void];

function isFunction<T>(obj: any): obj is T {
return typeof obj === 'function';
}

export function createUseStorageState(nullishStorage: Storage | null) {
function useStorageState<T>(
key: string,
defaultValue?: T | IFuncUpdater<T>,
): StorageStateResult<T> {
const storage = nullishStorage as Storage;
const [state, setState] = useState<T | undefined>(() => getStoredValue());
useUpdateEffect(() => {
setState(getStoredValue());
}, [key]);

function getStoredValue() {
const raw = storage.getItem(key);
if (raw) {
try {
return JSON.parse(raw);
} catch (e) {}
}
if (isFunction<IFuncUpdater<T>>(defaultValue)) {
return defaultValue();
}
return defaultValue;
}

const updateState = useCallback(
(value?: T | IFuncUpdater<T>) => {
if (typeof value === 'undefined') {
storage.removeItem(key);
setState(undefined);
} else if (isFunction<IFuncUpdater<T>>(value)) {
const previousState = getStoredValue();
const currentState = value(previousState);
storage.setItem(key, JSON.stringify(currentState));
setState(currentState);
} else {
storage.setItem(key, JSON.stringify(value));
setState(value);
}
},
[key],
);

return [state, updateState];
}
if (!nullishStorage) {
return function (defaultValue: any) {
return [
isFunction<IFuncUpdater<any>>(defaultValue) ? defaultValue() : defaultValue,
() => {},
];
} as typeof useStorageState;
}
return useStorageState;
}
17 changes: 4 additions & 13 deletions packages/hooks/src/useLocalStorageState/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import useStorageState from '../useStorageState';
import { createUseStorageState } from '../createUseStorageState';

function useLocalStorageState<T = undefined>(
key: string,
): [T | undefined, (value?: T | ((previousState?: T) => T)) => void];

function useLocalStorageState<T>(
key: string,
defaultValue: T | (() => T),
): [T, (value?: T | ((previousState: T) => T)) => void];

function useLocalStorageState<T>(key: string, defaultValue?: T | (() => T)) {
return useStorageState(() => localStorage, key, defaultValue);
}
const useLocalStorageState = createUseStorageState(
typeof window === 'object' ? window.localStorage : null,
);

export default useLocalStorageState;
17 changes: 4 additions & 13 deletions packages/hooks/src/useSessionStorageState/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import useStorageState from '../useStorageState';
import { createUseStorageState } from '../createUseStorageState';

function useSessionStorageState<T = undefined>(
key: string,
): [T | undefined, (value?: T | ((previousState?: T) => T)) => void];

function useSessionStorageState<T>(
key: string,
defaultValue: T | (() => T),
): [T, (value?: T | ((previousState: T) => T)) => void];

function useSessionStorageState<T>(key: string, defaultValue?: T | (() => T)) {
return useStorageState(() => sessionStorage, key, defaultValue);
}
const useSessionStorageState = createUseStorageState(
typeof window === 'object' ? window.sessionStorage : null,
);

export default useSessionStorageState;
70 changes: 0 additions & 70 deletions packages/hooks/src/useStorageState/index.ts

This file was deleted.

0 comments on commit 712b04b

Please sign in to comment.