Skip to content

Commit

Permalink
feat: add useRecoilQuery
Browse files Browse the repository at this point in the history
  • Loading branch information
salvoravida committed Aug 18, 2022
1 parent 8e8c958 commit a5aeb3a
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 2 deletions.
10 changes: 8 additions & 2 deletions packages/recoil-toolkit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "recoil-toolkit",
"version": "0.2.1",
"version": "0.2.4",
"description": "recoil-toolkit",
"main": "./build/es5/index.js",
"module": "./build/es6/index.js",
Expand Down Expand Up @@ -45,11 +45,16 @@
"homepage": "https://github.com/salvoravida/recoil-toolkit#readme",
"peerDependencies": {
"react": "^16.8.3 || ^17 || ^18",
"recoil": "^0.7.5"
"recoil": "^0.7.5",
"redux": "^4.2.0",
"axios": "^0.27.2"
},
"peerDependenciesMeta": {
"redux": {
"optional": true
},
"axios": {
"optional": true
}
},
"dependencies": {
Expand All @@ -60,6 +65,7 @@
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^28.1.6",
"@types/react": "^17.0.48",
"axios": "^0.27.2",
"jest": "^28.1.3",
"jest-environment-jsdom": "^28.1.3",
"react": "^17.0.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/recoil-toolkit/src/_core/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * from './useRecoilRequest';
export * from './useRecoilAsyncValue';
export * from './useRecoilLocalTask';
export * from './recoilStore';
export * from './useRecoilQuery';
export * from './signals';
13 changes: 13 additions & 0 deletions packages/recoil-toolkit/src/_core/hooks/signals/axios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Axios from 'axios';
import { addCancelSignal } from './store';

export function getAxiosToken(key: string) {
const newTokenSource = Axios.CancelToken.source();
addCancelSignal(key, {
signal: newTokenSource.token,
cancel: () => {
newTokenSource.cancel();
},
});
return newTokenSource.token;
}
12 changes: 12 additions & 0 deletions packages/recoil-toolkit/src/_core/hooks/signals/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { addCancelSignal } from './store';

export function getFetchSignal(key: string) {
const newAbortController = new AbortController();
addCancelSignal(key, {
signal: newAbortController.signal,
cancel: () => {
newAbortController.abort();
},
});
return newAbortController.signal;
}
3 changes: 3 additions & 0 deletions packages/recoil-toolkit/src/_core/hooks/signals/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './axios';
export * from './fetch';
export * from './store';
36 changes: 36 additions & 0 deletions packages/recoil-toolkit/src/_core/hooks/signals/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
let instanceId = 0;
function getInstanceId() {
instanceId += 1;
return instanceId;
}

export interface CancelSignal {
signal: unknown;
cancel: () => void;
}

const signalStore: {
[key: string]: {
[instance: number]: CancelSignal;
};
} = {};

export function addCancelSignal(key: string, signal: CancelSignal) {
if (!signalStore[key]) {
signalStore[key] = {};
}
signalStore[key][getInstanceId()] = signal;
}

export function doCancelSignal(key: string) {
if (signalStore[key]) {
Object.values(signalStore[key]).forEach((abortsignal) => {
try {
abortsignal.cancel();
} catch {
// ignore
}
});
signalStore[key] = {};
}
}
62 changes: 62 additions & 0 deletions packages/recoil-toolkit/src/_core/hooks/useRecoilQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useEffect, useRef } from 'react';
import { RecoilValue, useRecoilRefresher_UNSTABLE, useRecoilValueLoadable } from 'recoil';
import { doCancelSignal } from './signals/store';

export type RecoilQueryValue<V> = {
loading: boolean;
data?: V;
error?: unknown;
refresh: () => void;
};

export type RecoilQueryOptions = {
refreshOnMount?: 'always' | 'error';
cancelOnUnmount?: boolean | (() => void);
};

//todo freeze options object

export const useRecoilQuery = <V>(
selector: RecoilValue<V>,
options?: RecoilQueryOptions,
): RecoilQueryValue<V> => {
const { state, contents } = useRecoilValueLoadable<V>(selector);
const loading = state === 'loading';
const error = state === 'hasError' ? contents : undefined;
const data = (state === 'hasValue' ? contents : undefined) as V;

const lastData = useRef<V>();

useEffect(() => {
if (data !== undefined) {
lastData.current = data;
}
}, [data]);

const refresh = useRecoilRefresher_UNSTABLE(selector);

useEffect(() => {
if (options?.refreshOnMount === 'always' || (options?.refreshOnMount === 'error' && error)) {
refresh();
}
}, []); //eslint-disable-line

useEffect(
() => () => {
if (options?.cancelOnUnmount === true) {
doCancelSignal(selector.key);
}
if (typeof options?.cancelOnUnmount === 'function') {
options?.cancelOnUnmount();
}
},
[], //eslint-disable-line
);

return {
loading,
data: data !== undefined ? data : lastData.current,
error,
refresh,
};
};
13 changes: 13 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4036,6 +4036,14 @@ axe-core@^4.4.3:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.3.tgz#11c74d23d5013c0fa5d183796729bc3482bd2f6f"
integrity sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==

axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
dependencies:
follow-redirects "^1.14.9"
form-data "^4.0.0"

axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
Expand Down Expand Up @@ -7025,6 +7033,11 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==

follow-redirects@^1.14.9:
version "1.15.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==

for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
Expand Down

0 comments on commit a5aeb3a

Please sign in to comment.