@decathlon/moon
Advanced tools
Comparing version 1.0.0 to 2.0.0
@@ -1,5 +0,5 @@ | ||
export { default as MoonClient } from "./moonClient"; | ||
export * from "./moonClient"; | ||
export { default as MoonProvider } from "./moonProvider"; | ||
export * from "./moonProvider"; | ||
export { default as MoonClient } from "./moon-client"; | ||
export * from "./moon-client"; | ||
export { default as MoonProvider } from "./moon-provider"; | ||
export * from "./moon-provider"; | ||
export { default as Query } from "./query"; | ||
@@ -13,4 +13,5 @@ export * from "./query"; | ||
export * from "./mutation-hook"; | ||
export * from "./typing"; | ||
export * from "./utils"; | ||
export * from "./redux"; | ||
export * from "./hooks"; | ||
export { default as getMoonStore } from "./store"; | ||
export * from "./store"; |
@@ -1,5 +0,5 @@ | ||
export { default as MoonClient } from "./moonClient"; | ||
export * from "./moonClient"; | ||
export { default as MoonProvider } from "./moonProvider"; | ||
export * from "./moonProvider"; | ||
export { default as MoonClient } from "./moon-client"; | ||
export * from "./moon-client"; | ||
export { default as MoonProvider } from "./moon-provider"; | ||
export * from "./moon-provider"; | ||
export { default as Query } from "./query"; | ||
@@ -14,3 +14,5 @@ export * from "./query"; | ||
export * from "./utils"; | ||
export * from "./redux"; | ||
export * from "./hooks"; | ||
export { default as getMoonStore } from "./store"; | ||
export * from "./store"; | ||
//# sourceMappingURL=index.js.map |
import { AxiosRequestConfig } from "axios"; | ||
import { MutateType } from "./moonClient"; | ||
import { MutateType } from "./moon-client"; | ||
import { Nullable } from "./typing"; | ||
@@ -4,0 +4,0 @@ export interface IMutationActions { |
@@ -12,6 +12,5 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import StaticAxios from "axios"; | ||
import { useMoonClient } from "./moonClient"; | ||
import { usePrevValue } from "./utils"; | ||
import { usePrevValue, useMoon } from "./hooks"; | ||
export default function useMutation({ source, type, endPoint, variables, options, onResponse, onError }) { | ||
const { client } = useMoonClient(); | ||
const { client } = useMoon(); | ||
const { value } = usePrevValue(variables); | ||
@@ -39,3 +38,2 @@ const [state, setState] = React.useState({ | ||
try { | ||
// @ts-ignore API context initialized to null | ||
const response = (yield client.mutate(source, endPoint, type, variables, Object.assign(Object.assign({}, options), { cancelToken: cancelSourceRef.current && cancelSourceRef.current.token }))); | ||
@@ -42,0 +40,0 @@ setState(Object.assign(Object.assign({}, state), { loading: false, response })); |
/// <reference types="react" /> | ||
import { AxiosResponse } from "axios"; | ||
import { MutateType } from "./moonClient"; | ||
import { MutateType } from "./moon-client"; | ||
import { IMutationActions, IMutationState, IMutationProps } from "./mutation-hook"; | ||
@@ -5,0 +5,0 @@ import { Nullable } from "./typing"; |
@@ -13,3 +13,3 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
import * as React from "react"; | ||
import { MutateType } from "./moonClient"; | ||
import { MutateType } from "./moon-client"; | ||
import useMutation from "./mutation-hook"; | ||
@@ -16,0 +16,0 @@ // @ts-ignore ignore children type |
import { AxiosRequestConfig } from "axios"; | ||
import { IQueriesResult } from "./redux/reducers"; | ||
import { QueryState } from "./store"; | ||
export interface QueriesIds { | ||
@@ -15,7 +15,2 @@ [queryId: string]: string; | ||
} | ||
export declare enum MoonNetworkStatus { | ||
Ready = 1, | ||
Fetch = 2, | ||
Finished = 3 | ||
} | ||
export interface IQueryProps<QueryData = any, QueryVariables = any, DeserializedData = QueryData> { | ||
@@ -34,9 +29,5 @@ id?: string; | ||
} | ||
export interface IQueryState<QueryData = any> { | ||
loading: boolean; | ||
error: any; | ||
export interface IQueryState<QueryData = any> extends QueryState { | ||
data?: QueryData; | ||
networkStatus: MoonNetworkStatus; | ||
} | ||
export default function useQuery<QueryData = any, QueryVariables = any, DeserializedData = QueryData>({ id, source, endPoint, options, variables, fetchPolicy, deserialize, onResponse, onError, fetchOnMount, autoRefetchOnUpdate }: IQueryProps<QueryData, QueryVariables, DeserializedData>): [IQueryState<DeserializedData>, IQueryActions]; | ||
export declare function useQueriesResult(queriesIds: QueriesIds): IQueriesResult; |
@@ -12,6 +12,5 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import StaticAxios from "axios"; | ||
import { createSelector } from "reselect"; | ||
import { useSelector, shallowEqual } from "react-redux"; | ||
import { useMoonClient } from "./moonClient"; | ||
import { usePrevValue } from "./utils"; | ||
import { usePrevValue, useMoon, useQueryState } from "./hooks"; | ||
import { MoonNetworkStatus } from "./store"; | ||
import { getQueryId } from "./utils"; | ||
export var FetchPolicy; | ||
@@ -26,42 +25,11 @@ (function (FetchPolicy) { | ||
})(FetchPolicy || (FetchPolicy = {})); | ||
export var MoonNetworkStatus; | ||
(function (MoonNetworkStatus) { | ||
MoonNetworkStatus[MoonNetworkStatus["Ready"] = 1] = "Ready"; | ||
MoonNetworkStatus[MoonNetworkStatus["Fetch"] = 2] = "Fetch"; | ||
MoonNetworkStatus[MoonNetworkStatus["Finished"] = 3] = "Finished"; | ||
})(MoonNetworkStatus || (MoonNetworkStatus = {})); | ||
export default function useQuery({ id, source, endPoint, options, variables, fetchPolicy = FetchPolicy.CacheAndNetwork, deserialize, onResponse, onError, fetchOnMount = true, autoRefetchOnUpdate = true }) { | ||
const { client } = useMoonClient(); | ||
const { client, store } = useMoon(); | ||
const isInitialMount = React.useRef(true); | ||
const cancelSourceRef = React.useRef(); | ||
const { value, prevValue } = usePrevValue(variables); | ||
const queryId = React.useMemo(() => client && client.getQueryId(id, source, endPoint, variables), [ | ||
client, | ||
id, | ||
source, | ||
endPoint, | ||
variables | ||
]); | ||
const useCache = React.useMemo(() => [FetchPolicy.CacheFirst, FetchPolicy.CacheAndNetwork].includes(fetchPolicy), [ | ||
fetchPolicy | ||
]); | ||
const cache = useSelector((state) => queryId && state.queriesResult[queryId]); | ||
const [state, setState] = React.useState({ | ||
data: useCache && cache ? cache : undefined, | ||
loading: false, | ||
networkStatus: MoonNetworkStatus.Ready, | ||
error: null | ||
}); | ||
const { value: currentVariables, prevValue: prevVariables } = usePrevValue(variables); | ||
const queryId = React.useMemo(() => getQueryId(id, source, endPoint, variables), [client, id, source, endPoint, variables]); | ||
const state = useQueryState(queryId); | ||
const { data, loading, error, networkStatus } = state; | ||
React.useEffect(() => { | ||
if (data !== cache) { | ||
if ((networkStatus === MoonNetworkStatus.Ready && useCache) || networkStatus === MoonNetworkStatus.Finished) { | ||
setState(Object.assign(Object.assign({}, state), { data: cache })); | ||
} | ||
if (networkStatus === MoonNetworkStatus.Fetch) { | ||
setState(Object.assign(Object.assign({}, state), { data: cache, loading: false, networkStatus: MoonNetworkStatus.Finished })); | ||
} | ||
} | ||
}, [cache]); | ||
React.useEffect(() => { | ||
cancelSourceRef.current = StaticAxios.CancelToken.source(); | ||
@@ -77,14 +45,14 @@ if (isInitialMount.current) { | ||
} | ||
// @ts-ignore can't be undefined | ||
// @ts-ignore cancelSourceRef.current can't be undefined | ||
return () => cancelSourceRef.current.cancel(); | ||
}, [value, endPoint, source]); | ||
}, [currentVariables, endPoint, source]); | ||
const cancel = () => { | ||
if (cancelSourceRef.current) { | ||
cancelSourceRef.current.cancel(); | ||
setState(Object.assign(Object.assign({}, state), { loading: false, networkStatus: MoonNetworkStatus.Finished })); | ||
store.setQueryState(queryId, Object.assign(Object.assign({}, state), { loading: false, networkStatus: MoonNetworkStatus.Finished })); | ||
} | ||
}; | ||
const fetch = () => __awaiter(this, void 0, void 0, function* () { | ||
if (data && value === prevValue && FetchPolicy.CacheFirst === fetchPolicy) { | ||
setState(Object.assign(Object.assign({}, state), { loading: false, networkStatus: MoonNetworkStatus.Finished, error: null })); | ||
if (data && currentVariables === prevVariables && FetchPolicy.CacheFirst === fetchPolicy) { | ||
store.setQueryState(queryId, Object.assign(Object.assign({}, state), { loading: false, networkStatus: MoonNetworkStatus.Finished, error: null })); | ||
if (onResponse) { | ||
@@ -95,7 +63,7 @@ onResponse(data); | ||
else { | ||
setState(Object.assign(Object.assign({}, state), { loading: true, networkStatus: MoonNetworkStatus.Fetch, error: null })); | ||
const reponse = FetchPolicy.NetworkOnly === fetchPolicy ? undefined : data; | ||
store.setQueryState(queryId, Object.assign(Object.assign({}, state), { loading: true, networkStatus: MoonNetworkStatus.Fetch, error: null, data: reponse })); | ||
try { | ||
// the client.query (see MoonCient.query) will update the cache and consequently the state of this useQuery hook | ||
// @ts-ignore API context initialized to null | ||
const deserializedResponse = yield client.query(id, source, endPoint, variables, deserialize, Object.assign(Object.assign({}, options), { cancelToken: cancelSourceRef.current && cancelSourceRef.current.token })); | ||
const deserializedResponse = yield client.query(source, endPoint, variables, deserialize, Object.assign(Object.assign({}, options), { cancelToken: cancelSourceRef.current && cancelSourceRef.current.token })); | ||
store.setQueryState(queryId, Object.assign(Object.assign({}, state), { data: deserializedResponse, loading: false, networkStatus: MoonNetworkStatus.Finished })); | ||
if (onResponse) { | ||
@@ -109,3 +77,3 @@ onResponse(deserializedResponse); | ||
} | ||
setState(Object.assign(Object.assign({}, state), { loading: false, networkStatus: MoonNetworkStatus.Finished, error: err })); | ||
store.setQueryState(queryId, Object.assign(Object.assign({}, state), { loading: false, networkStatus: MoonNetworkStatus.Finished, error: err })); | ||
if (onError) { | ||
@@ -122,9 +90,2 @@ onError(err); | ||
} | ||
const selectQueriesResult = createSelector((state) => state.queriesResult, (_, queriesIds) => queriesIds, (queriesResult, queriesIds) => Object.keys(queriesIds).reduce((result, queryId) => { | ||
result[queriesIds[queryId]] = queriesResult[queryId]; | ||
return result; | ||
}, {})); | ||
export function useQueriesResult(queriesIds) { | ||
return useSelector((state) => selectQueriesResult(state, queriesIds), shallowEqual); | ||
} | ||
//# sourceMappingURL=query-hook.js.map |
@@ -1,4 +0,6 @@ | ||
/// <reference types="react" /> | ||
import * as React from "react"; | ||
import { Nullable } from "./typing"; | ||
import { IQueryProps, IQueryState, IQueryActions, FetchPolicy } from "./query-hook"; | ||
import { ResultProps } from "./hooks"; | ||
import { QueriesResults } from "./store"; | ||
export declare type QueryChildren<QueryData> = (props: IQueryChildrenProps<QueryData>) => Nullable<JSX.Element | JSX.Element[]>; | ||
@@ -20,2 +22,4 @@ export interface IQueryChildrenProps<QueryData = any> extends IQueryState<QueryData> { | ||
} | ||
export declare function withQueryResult<Props = any, WrappedComponentPropsWithoutQuery = Props, Data = any, QueryResultProps = ResultProps>(queryId: string, resutToProps?: (result?: Data) => QueryResultProps): (WrappedComponent: React.ComponentClass<Props, any> | React.FunctionComponent<Props>) => React.ForwardRefExoticComponent<React.PropsWithoutRef<WrappedComponentPropsWithoutQuery> & React.RefAttributes<any>>; | ||
export declare function withQueriesResults<Props = any, WrappedComponentPropsWithoutQuery = Props, Data = any, QueryResultProps = ResultProps>(queriesIds: string[], resultsToProps?: (results: QueriesResults<Data>) => QueryResultProps): (WrappedComponent: React.ComponentClass<Props, any> | React.FunctionComponent<Props>) => React.ForwardRefExoticComponent<React.PropsWithoutRef<WrappedComponentPropsWithoutQuery> & React.RefAttributes<any>>; | ||
export default Query; |
@@ -14,2 +14,3 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
import useQuery, { FetchPolicy } from "./query-hook"; | ||
import { useQueryResult, useQueriesResults } from "./hooks"; | ||
// @ts-ignore ignore children type | ||
@@ -30,3 +31,30 @@ export const DumbQuery = React.memo(function DumbQuery(props) { | ||
}; | ||
export function withQueryResult(queryId, resutToProps) { | ||
return (WrappedComponent) => { | ||
const WithQueryComponent = props => { | ||
const { forwardedRef } = props, rest = __rest(props, ["forwardedRef"]); | ||
const queryResult = useQueryResult(queryId, resutToProps); | ||
const queryProps = resutToProps ? queryResult : { [queryId]: queryResult }; | ||
// @ts-ignore I don't know how to implement this without breaking out of the types. | ||
return React.createElement(WrappedComponent, Object.assign({ ref: forwardedRef }, queryProps, rest)); | ||
}; | ||
return React.forwardRef((props, ref) => { | ||
return React.createElement(WithQueryComponent, Object.assign({ forwardedRef: ref }, props)); | ||
}); | ||
}; | ||
} | ||
export function withQueriesResults(queriesIds, resultsToProps) { | ||
return (WrappedComponent) => { | ||
const WithQueryComponent = props => { | ||
const { forwardedRef } = props, rest = __rest(props, ["forwardedRef"]); | ||
const queryResult = useQueriesResults(queriesIds, resultsToProps); | ||
// @ts-ignore I don't know how to implement this without breaking out of the types. | ||
return React.createElement(WrappedComponent, Object.assign({ ref: forwardedRef }, queryResult, rest)); | ||
}; | ||
return React.forwardRef((props, ref) => { | ||
return React.createElement(WithQueryComponent, Object.assign({ forwardedRef: ref }, props)); | ||
}); | ||
}; | ||
} | ||
export default Query; | ||
//# sourceMappingURL=query.js.map |
@@ -0,1 +1,5 @@ | ||
/// <reference types="react" /> | ||
export declare type Nullable<P> = P | null; | ||
export declare type PropsWithForwardRef<P, R> = P & { | ||
forwardedRef?: React.RefObject<R>; | ||
}; |
{ | ||
"name": "@decathlon/moon", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "A featured, production ready caching REST client for every React UI", | ||
@@ -12,18 +12,13 @@ "main": "dist/index.js", | ||
"axios": "~0.19.0", | ||
"lodash": "~4.17.15", | ||
"object-hash": "~2.0.0", | ||
"qs": "~6.9.1", | ||
"redux": "~4.0.4", | ||
"reselect": "~4.0.0" | ||
"qs": "~6.9.1" | ||
}, | ||
"peerDependencies": { | ||
"react": "^16.12.0", | ||
"react-redux": "~7.1.3" | ||
"react": "^16.12.0" | ||
}, | ||
"devDependencies": { | ||
"@testing-library/react": "~9.3.2", | ||
"@testing-library/react": "^9.4.0", | ||
"@testing-library/react-hooks": "~3.2.1", | ||
"@types/enzyme": "~3.10.3", | ||
"@types/jest": "~24.0.18", | ||
"@types/lodash": "~4.14.149", | ||
"@types/node": "~12.12.11", | ||
@@ -34,5 +29,4 @@ "@types/object-hash": "~1.3.0", | ||
"@types/react-dom": "~16.9.4", | ||
"@types/react-redux": "~7.1.5", | ||
"@typescript-eslint/eslint-plugin": "~2.9.0", | ||
"@typescript-eslint/parser": "~2.9.0", | ||
"@typescript-eslint/eslint-plugin": "^2.12.0", | ||
"@typescript-eslint/parser": "^2.12.0", | ||
"enzyme": "~3.10.0", | ||
@@ -44,6 +38,6 @@ "enzyme-adapter-react-16": "~1.15.1", | ||
"eslint-formatter-pretty": "~3.0.1", | ||
"eslint-plugin-import": "~2.18.2", | ||
"eslint-plugin-jest": "~23.0.4", | ||
"eslint-plugin-import": "^2.19.1", | ||
"eslint-plugin-jest": "^23.1.1", | ||
"eslint-plugin-jsx-a11y": "~6.2.3", | ||
"eslint-plugin-react": "~7.16.0", | ||
"eslint-plugin-react": "^7.17.0", | ||
"eslint-plugin-react-hooks": "~2.3.0", | ||
@@ -57,3 +51,2 @@ "husky": "~3.1.0", | ||
"react-dom": "~16.12.0", | ||
"react-redux": "~7.1.3", | ||
"rimraf": "~3.0.0", | ||
@@ -60,0 +53,0 @@ "ts-jest": "~24.2.0", |
132
README.md
@@ -44,27 +44,2 @@ # <img src='images/moon-title.png' height='50' alt='Moon Logo'/> | ||
For this first version we use Redux as a cache system. If you are using Redux, you must wrap MoonProvider with the Redux provider like this: | ||
```js | ||
import { MoonProvider } from "@decathlon/moon"; | ||
const links = [ | ||
{ | ||
id: "FOO", | ||
baseUrl: "http://foo.com" | ||
} | ||
]; | ||
const App = () => { | ||
return ( | ||
<Provider store={yourReduxStore}> | ||
<MoonProvider links={links} store={yourReduxStore}> | ||
<MyComponent /> | ||
</MoonProvider> | ||
</Provider> | ||
); | ||
}; | ||
``` | ||
Once your **MoonProvider** is hooked up, you're ready to start requesting data with the Query component or with the useQuery hook! | ||
@@ -146,27 +121,118 @@ | ||
Sometimes we need to retrieve the result of a query in another component. useQueriesResult allows you to do this. For that, it is enough to give him the ids of the queries: | ||
Sometimes we need to retrieve the state/result of a query in another component. useQueryResult/useQueriesResult/useQueryState/useQueriesStates allows you to do this. For that, it is enough to give him the id/ids of the query/queries: | ||
### useQueryState | ||
Updated when the query state is changed. The optional **stateToProps** function is used for selecting the part of the data from the query state that the connected component needs. | ||
```js | ||
import { useQueriesResult } from '@decathlon/moon'; | ||
import { useQueryState } from '@decathlon/moon'; | ||
const MyComponent = () => { | ||
// queryId is the id of the query and foo is the prop containing the result of the query | ||
const { foo } = useQueriesResult({ queryId: "foo" }); | ||
return <span>{foo ? "Loading..." : "success"}</span>; | ||
const stateToProps = (queryState) => queryState | ||
const { loading } = useQueryState("queryId", stateToProps); | ||
return <span>{loading ? "Loading..." : "success"}</span>; | ||
}; | ||
``` | ||
### useQueriesStates | ||
Updated when one of the query states is changed.The optional **statesToProps** function is used for selecting the part of the data from the query state that the connected component needs. | ||
```js | ||
import { useQueriesStates } from '@decathlon/moon'; | ||
const MyComponent = () => { | ||
const statesToProps = (queriesStates) => queriesStates | ||
const { queryId: { loading } } = useQueriesStates(["queryId"], statesToProps); | ||
return <span>{loading ? "Loading..." : "success"}</span>; | ||
}; | ||
``` | ||
### useQueryResult | ||
Updated only when the query result is changed. .The optional **resultToProps** function is used for selecting the part of the data from the query result that the connected component needs. | ||
```js | ||
import { useQueryResult } from '@decathlon/moon'; | ||
const MyComponent = () => { | ||
const resultToProps = (queryResult) => queryResult | ||
const result = useQueryResult("queryId", resultToProps); | ||
return <span>{...result...}</span>; | ||
}; | ||
``` | ||
### useQueriesResults | ||
Updated only when one of the query results is changed. The optional **statesToProps** function is used for selecting the part of the data from the queries results that the connected component needs. | ||
```js | ||
import { useQueriesResults } from '@decathlon/moon'; | ||
const MyComponent = () => { | ||
const resultsToProps = (queriesResults) => queriesResults | ||
const { queryId: queryIdResult } = useQueriesResults(["queryId"], statesToProps); | ||
return <span>{...queryIdResult...}</span>; | ||
}; | ||
``` | ||
### useMoon | ||
You can use the moon client directly like this: | ||
```js | ||
import { useMoonClient } from '@decathlon/moon'; | ||
import { useMoon } from '@decathlon/moon'; | ||
const MyComponent = () => { | ||
const { client } = useMoonClient(); | ||
const { client, store } = useMoon(); | ||
client.query(...); | ||
client.mutate(...); | ||
client.readQuery(...); | ||
store.readQuery(...); | ||
store.writeQuery(...); | ||
}; | ||
``` | ||
## HOCs | ||
### withMoon | ||
Same as useMoon hook. | ||
```js | ||
import { withMoon } from '@decathlon/moon'; | ||
const MyComponent = ({ client, store }) => { | ||
... | ||
}; | ||
export withMoon(MyComponent); | ||
``` | ||
### withQueryResult | ||
Same as useQueryResult hook. | ||
```js | ||
import { withQueryResult } from '@decathlon/moon'; | ||
const MyComponent = ({ queryId }) => { | ||
... | ||
}; | ||
export withQueryResult(queryId, resultToProps)(MyComponent); | ||
``` | ||
### withQueriesResults | ||
Same as useQueriesResults hook. | ||
```js | ||
import { withQueriesResults } from '@decathlon/moon'; | ||
const MyComponent = ({ queryId, queryId2 }) => { | ||
... | ||
}; | ||
export withQueriesResults([queryId, queryId2], resultsToProps)(MyComponent); | ||
``` | ||
## Query options | ||
@@ -173,0 +239,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
86418
4
33
833
357
4
- Removedlodash@~4.17.15
- Removedredux@~4.0.4
- Removedreselect@~4.0.0
- Removed@babel/runtime@7.26.0(transitive)
- Removedhoist-non-react-statics@3.3.2(transitive)
- Removedinvariant@2.2.4(transitive)
- Removedlodash@4.17.21(transitive)
- Removedreact-redux@7.1.3(transitive)
- Removedredux@4.0.5(transitive)
- Removedregenerator-runtime@0.14.1(transitive)
- Removedreselect@4.0.0(transitive)
- Removedsymbol-observable@1.2.0(transitive)