Skip to content

Commit

Permalink
v15 release
Browse files Browse the repository at this point in the history
BREAKING CHANGE: implementation of useMeasure and useLocalStorage changed
  • Loading branch information
streamich committed May 16, 2020
2 parents 3155583 + 8e6ec92 commit 0f82ba6
Show file tree
Hide file tree
Showing 20 changed files with 773 additions and 227 deletions.
99 changes: 98 additions & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,100 @@
# These are supported funding model platforms

github: streamich
github: [
"streamich",
"wardoost",
"xobotyi",
"Belco90",
"ankithkonda",
"ayush987goyal",
"NullVoxPopuli",
"lintuming",
"Granipouss",
"ythecombinator",
"james2406",
"jakapatb",
"MrHuangJser",
"zaguiini",
"ppeeou",
"liuyuchenzh",
"brickspert",
"artywhite",
"PetterIve",
"realdennis",
"lvl99",
"gelove",
"KusStar",
"xiaoxiangmoe",
"nmccready",
"mattleonowicz",
"kevinnorris",
"dubzzz",
"dependabot[bot]",
"ShizukuIchi",
"ManojBahuguna",
"Jivings",
"Dosant",
"zsh2401",
"xiaoboost",
"revskill10",
"mtinner",
"monkeywithacupcake",
"mitchheddles",
"maxzitron",
"macinjoke",
"jeetiss",
"ilyalesik",
"hijiangtao",
"f",
"elliottsj",
"droganov",
"denysdovhan",
"dabuside",
"benneq",
"azukaar",
"ariesjia",
"andrico1234",
"adesurirey",
"OBe95",
"FredyC",
"Cretezy",
"zyy7259",
"zslabs",
"vinitsood",
"uxitten",
"thevtm",
"tanem",
"suyingtao",
"srph",
"rkostrzewski",
"qianL93",
"o-alexandrov",
"nucleartux",
"natew",
"maxmalov",
"liaoyinglong",
"koenvanzuijlen",
"josmardias",
"jeemyeong",
"jazzqi",
"jakyle",
"jakeboone02",
"inker",
"glarivie",
"garrettmaring",
"dovidweisz",
"daniel-hauser",
"d-asensio",
"charlax",
"TylerR909",
"Rogdham",
"OctoD",
"MajorBreakfast",
"Jfelix61",
"Flydiverny",
"FlickerLogicalStack",
"DmacMcgreg",
"Dattaya",
"Andrey-Bazhanov",
"AlvaroBernalG"
]
2 changes: 1 addition & 1 deletion docs/useAsyncFn.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ const Demo = ({url}) => {
## Reference

```ts
useAsyncFn(fn, deps?: any[]);
useAsyncFn<Result, Args>(fn, deps?: any[], initialState?: AsyncState<Result>);
```
3 changes: 2 additions & 1 deletion docs/useLocalStorage.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ React side-effect hook that manages a single `localStorage` key.
import { useLocalStorage } from 'react-use';

const Demo = () => {
const [value, setValue] = useLocalStorage('my-key', 'foo');
const [value, setValue, remove] = useLocalStorage('my-key', 'foo');

return (
<div>
<div>Value: {value}</div>
<button onClick={() => setValue('bar')}>bar</button>
<button onClick={() => setValue('baz')}>baz</button>
<button onClick={() => remove()}>Remove</button>
</div>
);
};
Expand Down
15 changes: 15 additions & 0 deletions docs/useMeasure.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ const Demo = () => {
};
```

This hook uses [`ResizeObserver` API][resize-observer], if you want to support
legacy browsers, consider installing [`resize-observer-polyfill`][resize-observer-polyfill]
before running your app.

```js
if (!window.ResizeObserver) {
window.ResizeObserver = (await import('resize-observer-polyfill')).default;
}
```


## Related hooks

- [useSize](./useSize.md)


[resize-observer]: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
[resize-observer-polyfill]: https://www.npmjs.com/package/resize-observer-polyfill
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-use",
"version": "14.3.0",
"version": "15.0.0-alpha.1",
"description": "Collection of React Hooks",
"main": "lib/index.js",
"module": "esm/index.js",
Expand Down Expand Up @@ -169,7 +169,7 @@
"<rootDir>/tests/**/*.test.(ts|tsx)"
],
"setupFiles": [
"./tests/setupTests.ts"
"<rootDir>/tests/setupTests.ts"
]
}
}
10 changes: 4 additions & 6 deletions src/useAsync.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { DependencyList, useEffect } from 'react';
import useAsyncFn from './useAsyncFn';
import { FnReturningPromise } from './util';

export { AsyncState, AsyncFn } from './useAsyncFn';
export { AsyncState, AsyncFnReturn } from './useAsyncFn';

export default function useAsync<Result = any, Args extends any[] = any[]>(
fn: (...args: Args | []) => Promise<Result>,
deps: DependencyList = []
) {
const [state, callback] = useAsyncFn<Result, Args>(fn, deps, {
export default function useAsync<T extends FnReturningPromise>(fn: T, deps: DependencyList = []) {
const [state, callback] = useAsyncFn(fn, deps, {
loading: true,
});

Expand Down
32 changes: 18 additions & 14 deletions src/useAsyncFn.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/* eslint-disable */
import { DependencyList, useCallback, useState, useRef } from 'react';
import useMountedState from './useMountedState';
import { FnReturningPromise, PromiseType } from './util';

export type AsyncState<T> =
| {
loading: boolean;
error?: undefined;
value?: undefined;
}
| {
loading: true;
error?: Error | undefined;
value?: T;
}
| {
loading: false;
error: Error;
Expand All @@ -19,24 +25,22 @@ export type AsyncState<T> =
value: T;
};

export type AsyncFn<Result = any, Args extends any[] = any[]> = [
AsyncState<Result>,
(...args: Args | []) => Promise<Result>
];
type StateFromFnReturningPromise<T extends FnReturningPromise> = AsyncState<PromiseType<ReturnType<T>>>;

export default function useAsyncFn<Result = any, Args extends any[] = any[]>(
fn: (...args: Args | []) => Promise<Result>,
export type AsyncFnReturn<T extends FnReturningPromise = FnReturningPromise> = [StateFromFnReturningPromise<T>, T];

export default function useAsyncFn<T extends FnReturningPromise>(
fn: T,
deps: DependencyList = [],
initialState: AsyncState<Result> = { loading: false }
): AsyncFn<Result, Args> {
initialState: StateFromFnReturningPromise<T> = { loading: false }
): AsyncFnReturn<T> {
const lastCallId = useRef(0);
const [state, set] = useState<AsyncState<Result>>(initialState);

const isMounted = useMountedState();
const [state, set] = useState<StateFromFnReturningPromise<T>>(initialState);

const callback = useCallback((...args: Args | []) => {
const callback = useCallback((...args: Parameters<T>): ReturnType<T> => {
const callId = ++lastCallId.current;
set({ loading: true });
set(prevState => ({ ...prevState, loading: true }));

return fn(...args).then(
value => {
Expand All @@ -49,8 +53,8 @@ export default function useAsyncFn<Result = any, Args extends any[] = any[]>(

return error;
}
);
) as ReturnType<T>;
}, deps);

return [state, callback];
return [state, (callback as unknown) as T];
}
43 changes: 29 additions & 14 deletions src/useCopyToClipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,46 @@ const useCopyToClipboard = (): [CopyToClipboardState, (value: string) => void] =
});

const copyToClipboard = useCallback(value => {
if (!isMounted()) {
return;
}
let noUserInteraction;
let normalizedValue;
try {
if (process.env.NODE_ENV === 'development') {
if (typeof value !== 'string') {
console.error(`Cannot copy typeof ${typeof value} to clipboard, must be a string`);
}
// only strings and numbers casted to strings can be copied to clipboard
if (typeof value !== 'string' && typeof value !== 'number') {
const error = new Error(`Cannot copy typeof ${typeof value} to clipboard, must be a string`);
if (process.env.NODE_ENV === 'development') console.error(error);
setState({
value,
error,
noUserInteraction: true,
});
return;
}

const noUserInteraction = writeText(value);

if (!isMounted()) {
// empty strings are also considered invalid
else if (value === '') {
const error = new Error(`Cannot copy empty string to clipboard.`);
if (process.env.NODE_ENV === 'development') console.error(error);
setState({
value,
error,
noUserInteraction: true,
});
return;
}
normalizedValue = value.toString();
noUserInteraction = writeText(normalizedValue);
setState({
value,
value: normalizedValue,
error: undefined,
noUserInteraction,
});
} catch (error) {
if (!isMounted()) {
return;
}
setState({
value: undefined,
value: normalizedValue,
error,
noUserInteraction: true,
noUserInteraction,
});
}
}, []);
Expand Down
10 changes: 7 additions & 3 deletions src/useCustomCompareEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { DependencyList, EffectCallback, useEffect, useRef } from 'react';

const isPrimitive = (val: any) => val !== Object(val);

type DepsEqualFnType = (prevDeps: DependencyList, nextDeps: DependencyList) => boolean;
type DepsEqualFnType<TDeps extends DependencyList> = (prevDeps: TDeps, nextDeps: TDeps) => boolean;

const useCustomCompareEffect = (effect: EffectCallback, deps: DependencyList, depsEqual: DepsEqualFnType) => {
const useCustomCompareEffect = <TDeps extends DependencyList>(
effect: EffectCallback,
deps: TDeps,
depsEqual: DepsEqualFnType<TDeps>
) => {
if (process.env.NODE_ENV !== 'production') {
if (!(deps instanceof Array) || !deps.length) {
console.warn('`useCustomCompareEffect` should not be used with no dependencies. Use React.useEffect instead.');
Expand All @@ -21,7 +25,7 @@ const useCustomCompareEffect = (effect: EffectCallback, deps: DependencyList, de
}
}

const ref = useRef<DependencyList | undefined>(undefined);
const ref = useRef<TDeps | undefined>(undefined);

if (!ref.current || !depsEqual(deps, ref.current)) {
ref.current = deps;
Expand Down

0 comments on commit 0f82ba6

Please sign in to comment.