@proscom/prostore-react
Advanced tools
Comparing version 0.1.13 to 0.2.0
export * from './ProstoreContext'; | ||
export * from './ProstoreSsrContext'; | ||
export * from './useAsyncOperation'; | ||
export * from './useConnectStore'; | ||
@@ -4,0 +5,0 @@ export * from './useRequestStore'; |
export * from './ProstoreContext'; | ||
export * from './ProstoreSsrContext'; | ||
export * from './useAsyncOperation'; | ||
export * from './useConnectStore'; | ||
@@ -4,0 +5,0 @@ export * from './useRequestStore'; |
@@ -11,3 +11,3 @@ /// <reference types="react" /> | ||
*/ | ||
export declare const ProstoreContext: import("react").Context<IProstoreContext>; | ||
export declare const ProstoreContext: import("react").Context<IProstoreContext | null>; | ||
/** | ||
@@ -14,0 +14,0 @@ * Extracts store from the context based on the provided name, |
@@ -16,5 +16,8 @@ import { useContext, createContext } from 'react'; | ||
if (typeof storeOrName === 'string') { | ||
if (!context) { | ||
throw new Error("ProstoreContext is not provided"); | ||
} | ||
var store = context[storeOrName]; | ||
if (!store) { | ||
throw new Error("Store '" + storeOrName + "' is not registered in the context"); | ||
throw new Error("Store '" + storeOrName + "' is not registered in the ProstoreContext"); | ||
} | ||
@@ -21,0 +24,0 @@ return store; |
@@ -6,3 +6,3 @@ /// <reference types="react" /> | ||
*/ | ||
export declare const ProstoreSsrContext: import("react").Context<ProstoreSsrManager>; | ||
export declare const ProstoreSsrContext: import("react").Context<ProstoreSsrManager | null>; | ||
export declare type IStates = { | ||
@@ -9,0 +9,0 @@ [name: string]: any; |
@@ -5,2 +5,2 @@ import { IStore } from '@proscom/prostore'; | ||
*/ | ||
export declare function useConnectStore<State>(store: IStore<State>, setState: (state: State) => any): void; | ||
export declare function useConnectStore<State = any>(store: IStore<State>, setState: (state: State) => any): void; |
@@ -5,10 +5,11 @@ import { BehaviorSubject, Observable } from 'rxjs'; | ||
*/ | ||
export declare function useObservable<State>(obs$: Observable<State>, setState: (state: State) => any): void; | ||
export declare function useObservable<State = any>(obs$: Observable<State> | null | undefined, setState: (state: State) => any): void; | ||
/** | ||
* Subscribe to Observable with useState included | ||
*/ | ||
export declare function useObservableState<State>(obs$: Observable<State>, initialState?: State): State; | ||
export declare function useObservableState<State = any>(obs$: Observable<State> | null | undefined, initialState: State): State; | ||
export declare function useObservableState<State = any>(obs$: Observable<State> | null | undefined): State | null; | ||
/** | ||
* Subscribe to BehaviorSubject | ||
*/ | ||
export declare function useSubject<State>(sub$: BehaviorSubject<State>): State; | ||
export declare function useSubject<State = any>(sub$: BehaviorSubject<State> | null | undefined): State | null; |
@@ -7,2 +7,5 @@ import { useEffect, useState } from 'react'; | ||
useEffect(function () { | ||
if (!obs$) { | ||
return; | ||
} | ||
var sub = obs$.subscribe(function (state) { | ||
@@ -16,5 +19,2 @@ setState(state); | ||
} | ||
/** | ||
* Subscribe to Observable with useState included | ||
*/ | ||
export function useObservableState(obs$, initialState) { | ||
@@ -30,4 +30,5 @@ if (initialState === void 0) { initialState = null; } | ||
export function useSubject(sub$) { | ||
return useObservableState(sub$, sub$.value); | ||
var _a; | ||
return useObservableState(sub$, (_a = sub$ === null || sub$ === void 0 ? void 0 : sub$.value) !== null && _a !== void 0 ? _a : null); | ||
} | ||
//# sourceMappingURL=useObservable.js.map |
@@ -1,14 +0,13 @@ | ||
import { DependencyList } from 'react'; | ||
import { CheckRequestResult, CheckRequestStateFn, IRequestState, IRequestStoreOptions, RequestStore } from '@proscom/prostore'; | ||
export interface UseRequestStoreResult<Vars, Data, Options> { | ||
import { CheckRequestResult, CheckRequestStateFn, GetRequestStoreData, GetRequestStoreOptions, GetRequestStoreState, GetRequestStoreVars, RequestStore } from "@proscom/prostore"; | ||
export interface UseRequestStoreResult<Store extends RequestStore> { | ||
check: CheckRequestResult; | ||
state: IRequestState<Vars, Data>; | ||
load: (options?: Options) => Promise<IRequestState<Vars, Data>>; | ||
store: RequestStore<Vars, Data, Options>; | ||
state: GetRequestStoreState<Store>; | ||
load: (options?: GetRequestStoreOptions<Store>) => Promise<GetRequestStoreState<Store>>; | ||
store: Store; | ||
} | ||
export interface UseRequestOptions<Vars, Data> { | ||
export interface UseRequestOptions<Vars = any, Data = any> { | ||
checkRequest?: CheckRequestStateFn<Vars, Data>; | ||
} | ||
/** | ||
* Attached component to the provided store and requests data based on the variables and options | ||
* Attaches component to the provided store and requests data based on the variables and options | ||
* | ||
@@ -22,10 +21,2 @@ * @param storeOrName - RequestStore to subscribe to, or its name for it to be injected from the context | ||
*/ | ||
export declare function useRequestStore<Vars, Data, Options extends IRequestStoreOptions<Vars, Data>>(storeOrName: string | RequestStore<Vars, Data, Options>, variables: Vars, options?: Options, hookOptions?: UseRequestOptions<Vars, Data>): UseRequestStoreResult<Vars, Data, Options>; | ||
/** | ||
* The same as useRequestStore, but it uses variableCreator which is supplied to useMemo and | ||
* can be used to memoize query variables. This may be used when the default behavior of deeply | ||
* comparing variables is not preferable (i.e., it is not fast enough, or variables are not simple objects) | ||
* | ||
* @returns {{load, check, state}} - Current request state | ||
*/ | ||
export declare function useRequestStoreVars<Vars, Data, Options extends IRequestStoreOptions<Vars, Data>>(storeOrName: string | RequestStore<Vars, Data, Options>, variableCreator: () => Vars, args: DependencyList): UseRequestStoreResult<Vars, Data, Options>; | ||
export declare function useRequestStore<Store extends RequestStore>(storeOrName: string | Store, variables?: GetRequestStoreVars<Store> | undefined, options?: GetRequestStoreOptions<Store> | undefined, hookOptions?: UseRequestOptions<GetRequestStoreVars<Store>, GetRequestStoreData<Store>>): UseRequestStoreResult<Store>; |
@@ -1,8 +0,9 @@ | ||
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; | ||
import { checkRequestState, } from '@proscom/prostore'; | ||
import { useConnectStore } from './useConnectStore'; | ||
import { useContextStore } from './ProstoreContext'; | ||
import { ProstoreSsrContext } from './ProstoreSsrContext'; | ||
import { useContext, useEffect, useState } from "react"; | ||
import { checkRequestState } from "@proscom/prostore"; | ||
import { useLatestCallbackRef } from "@proscom/ui-react"; | ||
import { useConnectStore } from "./useConnectStore"; | ||
import { useContextStore } from "./ProstoreContext"; | ||
import { ProstoreSsrContext } from "./ProstoreSsrContext"; | ||
/** | ||
* Attached component to the provided store and requests data based on the variables and options | ||
* Attaches component to the provided store and requests data based on the variables and options | ||
* | ||
@@ -17,2 +18,3 @@ * @param storeOrName - RequestStore to subscribe to, or its name for it to be injected from the context | ||
export function useRequestStore(storeOrName, variables, options, hookOptions) { | ||
if (variables === void 0) { variables = undefined; } | ||
if (options === void 0) { options = undefined; } | ||
@@ -30,11 +32,6 @@ if (hookOptions === void 0) { hookOptions = {}; } | ||
// Memoized callback to request data | ||
var funcsRef = useRef({}); | ||
funcsRef.current.loadData = function (newOptions) { | ||
var loadData = useLatestCallbackRef(function (newOptions) { | ||
if (newOptions === void 0) { newOptions = undefined; } | ||
return store.loadData(variables, newOptions || options); | ||
}; | ||
var loadData = useCallback(function (newOptions) { | ||
if (newOptions === void 0) { newOptions = undefined; } | ||
return funcsRef.current.loadData(newOptions); | ||
}, []); | ||
}); | ||
// Request the data if it is should be requested | ||
@@ -58,13 +55,2 @@ useEffect(function () { | ||
} | ||
/** | ||
* The same as useRequestStore, but it uses variableCreator which is supplied to useMemo and | ||
* can be used to memoize query variables. This may be used when the default behavior of deeply | ||
* comparing variables is not preferable (i.e., it is not fast enough, or variables are not simple objects) | ||
* | ||
* @returns {{load, check, state}} - Current request state | ||
*/ | ||
export function useRequestStoreVars(storeOrName, variableCreator, args) { | ||
var variables = useMemo(variableCreator, args); | ||
return useRequestStore(storeOrName, variables); | ||
} | ||
//# sourceMappingURL=useRequestStore.js.map |
export * from './ProstoreContext'; | ||
export * from './ProstoreSsrContext'; | ||
export * from './useAsyncOperation'; | ||
export * from './useConnectStore'; | ||
@@ -4,0 +5,0 @@ export * from './useRequestStore'; |
@@ -6,2 +6,3 @@ "use strict"; | ||
tslib_1.__exportStar(require("./ProstoreSsrContext"), exports); | ||
tslib_1.__exportStar(require("./useAsyncOperation"), exports); | ||
tslib_1.__exportStar(require("./useConnectStore"), exports); | ||
@@ -8,0 +9,0 @@ tslib_1.__exportStar(require("./useRequestStore"), exports); |
@@ -11,3 +11,3 @@ /// <reference types="react" /> | ||
*/ | ||
export declare const ProstoreContext: import("react").Context<IProstoreContext>; | ||
export declare const ProstoreContext: import("react").Context<IProstoreContext | null>; | ||
/** | ||
@@ -14,0 +14,0 @@ * Extracts store from the context based on the provided name, |
@@ -19,5 +19,8 @@ "use strict"; | ||
if (typeof storeOrName === 'string') { | ||
if (!context) { | ||
throw new Error("ProstoreContext is not provided"); | ||
} | ||
var store = context[storeOrName]; | ||
if (!store) { | ||
throw new Error("Store '" + storeOrName + "' is not registered in the context"); | ||
throw new Error("Store '" + storeOrName + "' is not registered in the ProstoreContext"); | ||
} | ||
@@ -24,0 +27,0 @@ return store; |
@@ -6,3 +6,3 @@ /// <reference types="react" /> | ||
*/ | ||
export declare const ProstoreSsrContext: import("react").Context<ProstoreSsrManager>; | ||
export declare const ProstoreSsrContext: import("react").Context<ProstoreSsrManager | null>; | ||
export declare type IStates = { | ||
@@ -9,0 +9,0 @@ [name: string]: any; |
@@ -5,2 +5,2 @@ import { IStore } from '@proscom/prostore'; | ||
*/ | ||
export declare function useConnectStore<State>(store: IStore<State>, setState: (state: State) => any): void; | ||
export declare function useConnectStore<State = any>(store: IStore<State>, setState: (state: State) => any): void; |
@@ -5,10 +5,11 @@ import { BehaviorSubject, Observable } from 'rxjs'; | ||
*/ | ||
export declare function useObservable<State>(obs$: Observable<State>, setState: (state: State) => any): void; | ||
export declare function useObservable<State = any>(obs$: Observable<State> | null | undefined, setState: (state: State) => any): void; | ||
/** | ||
* Subscribe to Observable with useState included | ||
*/ | ||
export declare function useObservableState<State>(obs$: Observable<State>, initialState?: State): State; | ||
export declare function useObservableState<State = any>(obs$: Observable<State> | null | undefined, initialState: State): State; | ||
export declare function useObservableState<State = any>(obs$: Observable<State> | null | undefined): State | null; | ||
/** | ||
* Subscribe to BehaviorSubject | ||
*/ | ||
export declare function useSubject<State>(sub$: BehaviorSubject<State>): State; | ||
export declare function useSubject<State = any>(sub$: BehaviorSubject<State> | null | undefined): State | null; |
@@ -10,2 +10,5 @@ "use strict"; | ||
react_1.useEffect(function () { | ||
if (!obs$) { | ||
return; | ||
} | ||
var sub = obs$.subscribe(function (state) { | ||
@@ -20,5 +23,2 @@ setState(state); | ||
exports.useObservable = useObservable; | ||
/** | ||
* Subscribe to Observable with useState included | ||
*/ | ||
function useObservableState(obs$, initialState) { | ||
@@ -35,5 +35,6 @@ if (initialState === void 0) { initialState = null; } | ||
function useSubject(sub$) { | ||
return useObservableState(sub$, sub$.value); | ||
var _a; | ||
return useObservableState(sub$, (_a = sub$ === null || sub$ === void 0 ? void 0 : sub$.value) !== null && _a !== void 0 ? _a : null); | ||
} | ||
exports.useSubject = useSubject; | ||
//# sourceMappingURL=useObservable.js.map |
@@ -1,14 +0,13 @@ | ||
import { DependencyList } from 'react'; | ||
import { CheckRequestResult, CheckRequestStateFn, IRequestState, IRequestStoreOptions, RequestStore } from '@proscom/prostore'; | ||
export interface UseRequestStoreResult<Vars, Data, Options> { | ||
import { CheckRequestResult, CheckRequestStateFn, GetRequestStoreData, GetRequestStoreOptions, GetRequestStoreState, GetRequestStoreVars, RequestStore } from "@proscom/prostore"; | ||
export interface UseRequestStoreResult<Store extends RequestStore> { | ||
check: CheckRequestResult; | ||
state: IRequestState<Vars, Data>; | ||
load: (options?: Options) => Promise<IRequestState<Vars, Data>>; | ||
store: RequestStore<Vars, Data, Options>; | ||
state: GetRequestStoreState<Store>; | ||
load: (options?: GetRequestStoreOptions<Store>) => Promise<GetRequestStoreState<Store>>; | ||
store: Store; | ||
} | ||
export interface UseRequestOptions<Vars, Data> { | ||
export interface UseRequestOptions<Vars = any, Data = any> { | ||
checkRequest?: CheckRequestStateFn<Vars, Data>; | ||
} | ||
/** | ||
* Attached component to the provided store and requests data based on the variables and options | ||
* Attaches component to the provided store and requests data based on the variables and options | ||
* | ||
@@ -22,10 +21,2 @@ * @param storeOrName - RequestStore to subscribe to, or its name for it to be injected from the context | ||
*/ | ||
export declare function useRequestStore<Vars, Data, Options extends IRequestStoreOptions<Vars, Data>>(storeOrName: string | RequestStore<Vars, Data, Options>, variables: Vars, options?: Options, hookOptions?: UseRequestOptions<Vars, Data>): UseRequestStoreResult<Vars, Data, Options>; | ||
/** | ||
* The same as useRequestStore, but it uses variableCreator which is supplied to useMemo and | ||
* can be used to memoize query variables. This may be used when the default behavior of deeply | ||
* comparing variables is not preferable (i.e., it is not fast enough, or variables are not simple objects) | ||
* | ||
* @returns {{load, check, state}} - Current request state | ||
*/ | ||
export declare function useRequestStoreVars<Vars, Data, Options extends IRequestStoreOptions<Vars, Data>>(storeOrName: string | RequestStore<Vars, Data, Options>, variableCreator: () => Vars, args: DependencyList): UseRequestStoreResult<Vars, Data, Options>; | ||
export declare function useRequestStore<Store extends RequestStore>(storeOrName: string | Store, variables?: GetRequestStoreVars<Store> | undefined, options?: GetRequestStoreOptions<Store> | undefined, hookOptions?: UseRequestOptions<GetRequestStoreVars<Store>, GetRequestStoreData<Store>>): UseRequestStoreResult<Store>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useRequestStoreVars = exports.useRequestStore = void 0; | ||
exports.useRequestStore = void 0; | ||
var react_1 = require("react"); | ||
var prostore_1 = require("@proscom/prostore"); | ||
var ui_react_1 = require("@proscom/ui-react"); | ||
var useConnectStore_1 = require("./useConnectStore"); | ||
@@ -10,3 +11,3 @@ var ProstoreContext_1 = require("./ProstoreContext"); | ||
/** | ||
* Attached component to the provided store and requests data based on the variables and options | ||
* Attaches component to the provided store and requests data based on the variables and options | ||
* | ||
@@ -21,2 +22,3 @@ * @param storeOrName - RequestStore to subscribe to, or its name for it to be injected from the context | ||
function useRequestStore(storeOrName, variables, options, hookOptions) { | ||
if (variables === void 0) { variables = undefined; } | ||
if (options === void 0) { options = undefined; } | ||
@@ -34,11 +36,6 @@ if (hookOptions === void 0) { hookOptions = {}; } | ||
// Memoized callback to request data | ||
var funcsRef = react_1.useRef({}); | ||
funcsRef.current.loadData = function (newOptions) { | ||
var loadData = ui_react_1.useLatestCallbackRef(function (newOptions) { | ||
if (newOptions === void 0) { newOptions = undefined; } | ||
return store.loadData(variables, newOptions || options); | ||
}; | ||
var loadData = react_1.useCallback(function (newOptions) { | ||
if (newOptions === void 0) { newOptions = undefined; } | ||
return funcsRef.current.loadData(newOptions); | ||
}, []); | ||
}); | ||
// Request the data if it is should be requested | ||
@@ -63,14 +60,2 @@ react_1.useEffect(function () { | ||
exports.useRequestStore = useRequestStore; | ||
/** | ||
* The same as useRequestStore, but it uses variableCreator which is supplied to useMemo and | ||
* can be used to memoize query variables. This may be used when the default behavior of deeply | ||
* comparing variables is not preferable (i.e., it is not fast enough, or variables are not simple objects) | ||
* | ||
* @returns {{load, check, state}} - Current request state | ||
*/ | ||
function useRequestStoreVars(storeOrName, variableCreator, args) { | ||
var variables = react_1.useMemo(variableCreator, args); | ||
return useRequestStore(storeOrName, variables); | ||
} | ||
exports.useRequestStoreVars = useRequestStoreVars; | ||
//# sourceMappingURL=useRequestStore.js.map |
{ | ||
"name": "@proscom/prostore-react", | ||
"version": "0.1.13", | ||
"version": "0.2.0", | ||
"description": "Prostore hooks and utils for React", | ||
@@ -29,7 +29,8 @@ "author": "Andrew Starostin <a.starostin@proscom.ru>", | ||
"dependencies": { | ||
"@proscom/prostore": "^0.1.13", | ||
"@proscom/prostore": "^0.2.0", | ||
"@proscom/ui-react": "^0.0.6", | ||
"tslib": "^2.0.3" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^16.8.23", | ||
"@types/react": "^17.0.0", | ||
"react": "^17.0.1" | ||
@@ -41,3 +42,3 @@ }, | ||
"sideEffects": false, | ||
"gitHead": "3df77cce3fe186050039d517760d5c7bac7abd84" | ||
"gitHead": "41002836cd640f25af46a1bf029b92ecf117c572" | ||
} |
175
README.md
@@ -15,11 +15,15 @@ # `prostore-react` | ||
```javascript | ||
// IncStore.js | ||
```typescript | ||
// IncStore.ts | ||
import { BehaviorStore } from '@proscom/prostore'; | ||
const initialState = { | ||
export interface IncStoreState { | ||
number: number; | ||
} | ||
const initialState: IncStoreState = { | ||
number: 0 | ||
}; | ||
export class IncStore extends BehaviorStore { | ||
export class IncStore extends BehaviorStore<IncStoreState> { | ||
constructor() { | ||
@@ -37,4 +41,4 @@ super(initialState); | ||
```javascript | ||
// incStore.js | ||
```typescript | ||
// incStore.ts | ||
import { IncStore } from './IncStore'; | ||
@@ -44,2 +48,4 @@ export const incStore = new IncStore(); | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-basic-gsx5u?file=/src/stores/IncStore.ts) | ||
### `useStore` | ||
@@ -50,4 +56,4 @@ | ||
```jsx harmony | ||
import { useStore } from '@proscom/react'; | ||
```tsx | ||
import { useStore } from '@proscom/prostore-react'; | ||
@@ -74,2 +80,4 @@ // Импортируем любой store, расширяющий IStore | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-basic-gsx5u?file=/src/demo/Demo1.tsx) | ||
### `useStoreState` | ||
@@ -81,3 +89,3 @@ | ||
```jsx harmony | ||
```tsx | ||
function MyComponent() { | ||
@@ -89,2 +97,4 @@ const state = useStoreState(incStore); | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-basic-gsx5u?file=/src/demo/Demo2.tsx) | ||
### `ProstoreContext` | ||
@@ -96,7 +106,9 @@ | ||
```jsx harmony | ||
```typescript | ||
// stores.ts | ||
export const STORE_TEST = 'STORE_TEST'; | ||
``` | ||
```jsx harmony | ||
```tsx | ||
// index.ts | ||
import ReactDOM from 'react-dom'; | ||
@@ -124,5 +136,6 @@ import { STORE_TEST } from './stores'; | ||
```jsx harmony | ||
// App.js | ||
import { useStore } from '@proscom/react'; | ||
```tsx | ||
// App.ts | ||
import { useStore } from '@proscom/prostore-react'; | ||
import { IncStore } from './IncStore'; | ||
import { STORE_TEST } from './stores'; | ||
@@ -133,4 +146,10 @@ | ||
// то этот вызов полностью аналогичен useStore(incStore) | ||
const [state, store] = useStore(STORE_TEST); | ||
// При использовании с TypeScript необходимо указать тип стора | ||
// в качестве аргумента дженерика. Проще всего указать имя класс стора (IncStore). | ||
// При необходимости можно уменьшить связанность кода, реализовав | ||
// отдельный интерфейс, который реализуется классом стора, и указать | ||
// его здесь в качестве аргумента дженерика. | ||
const [state, store] = useStore<IncStore>(STORE_TEST); | ||
const onClick = () => { | ||
@@ -144,2 +163,4 @@ store.increment(); | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-basic-gsx5u?file=/src/demo/Demo3.tsx) | ||
### `useContextStore` | ||
@@ -152,4 +173,5 @@ | ||
```jsx harmony | ||
```tsx | ||
import { incStore } from './incStore'; | ||
function IncButton() { | ||
@@ -160,2 +182,4 @@ return <button onClick={() => incStore.increment()}>Increment</button>; | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-basic-gsx5u?file=/src/demo/Demo4.tsx) | ||
При использовании контекста можно получить доступ к стору | ||
@@ -166,7 +190,13 @@ с помощью хука `useContextStore`. По сравнению с использованием | ||
```jsx harmony | ||
import { useContextStore } from '@proscom/react'; | ||
```tsx | ||
import { useContextStore } from '@proscom/prostore-react'; | ||
import { IncStore } from './IncStore'; | ||
import { STORE_TEST } from './stores'; | ||
function IncButton() { | ||
const incStore = useContextStore(STORE_TEST); | ||
// При использовании с TypeScript необходимо указать тип стора | ||
// в качестве аргумента дженерика. Проще всего указать имя класс стора (IncStore). | ||
// При необходимости можно уменьшить связанность кода, реализовав | ||
// отдельный интерфейс, который реализуется классом стора, и указать | ||
// его здесь в качестве аргумента дженерика. | ||
const incStore = useContextStore<IncStore>(STORE_TEST); | ||
return <button onClick={() => incStore.increment()}>Increment</button>; | ||
@@ -176,2 +206,4 @@ } | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-basic-gsx5u?file=/src/demo/Demo5.tsx) | ||
### `useRequestStore` | ||
@@ -184,3 +216,3 @@ | ||
```jsx harmony | ||
```tsx | ||
import { AxiosQueryStore } from '@proscom/prostore-axios'; | ||
@@ -192,4 +224,25 @@ import { useRequestStore } from '@proscom/prostore-react'; | ||
// http-запросов с помощью axios | ||
const store = new AxiosQueryStore(/* ... */); | ||
// Определяем динамические параметры запроса | ||
export interface DataQueryStoreVariables { | ||
params?: { | ||
page?: number; | ||
}; | ||
} | ||
// Определяем тип результата запроса | ||
export interface DataQueryStoreData { | ||
message: string; | ||
} | ||
// Создаём стор, который будет хранить результат запроса. | ||
// Сам запрос вызовется, только при подключении стора в компонент | ||
const store = new AxiosQueryStore<DataQueryStoreVariables, DataQueryStoreData>({ | ||
client: axios.create(), | ||
query: { | ||
url: '/data.json', | ||
method: 'get' | ||
} | ||
}); | ||
function MyComponent() { | ||
@@ -206,2 +259,4 @@ // Параметры запроса | ||
// Подключаем стор в компонент и выполняем запрос при необходимости | ||
// По факту выполнения запроса компонент ререндерится | ||
const query = useRequestStore(store, variables, options); | ||
@@ -229,2 +284,4 @@ | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-use-request-store-py67z?file=/src/demo/Demo1.tsx) | ||
При каждом рендере `useRequestStore` **глубоко** сравнивает | ||
@@ -239,12 +296,80 @@ предыдущие переменные с новыми, и если есть отличия, то | ||
`useRequestStore` можно также использовать с контекстом: | ||
`useRequestStore` можно также использовать с контекстом. | ||
В таком случае необходимо указать тип переменных и тип результата аргументами дженерика: | ||
```jsx harmony | ||
```tsx | ||
import { useRequestStore } from '@proscom/prostore-react'; | ||
import { STORE_TEST } from './stores'; | ||
import { useRequestStore } from '@proscom/prostore-react'; | ||
import { StoreTestVariables, StoreTestData } from './stores/StoreTest'; | ||
function MyComponent() { | ||
const variables = {}; | ||
const query = useRequestStore(STORE_TEST, variables); | ||
const query = useRequestStore<StoreTestVariables, StoreTestData>( | ||
STORE_TEST, | ||
variables | ||
); | ||
// ... | ||
} | ||
``` | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-use-request-store-py67z?file=/src/demo/Demo2.tsx) | ||
### `useAsyncOperation` | ||
`RequestStore` представляет собой реактивную зависимость результата запроса от переменных (параметров запроса). | ||
Это значит, что момент выполнения запроса определяется автоматически. | ||
Такая семантика подходит только запросов, удовлетворяющим свойствам чистой функции | ||
(возвращающих одни и те же значения для одних и тех же переменных и не выполняющим побочных эффектов), | ||
например для GET HTTP запросов на получение данных и запросов GraphQL Query. | ||
Мутирующие запросы (POST HTTP или GraphQL Mutation) следует вызывать в коде императивно | ||
в нужный момент (например, в ответ на клик пользователя по кнопке). | ||
Мутирующий запрос может не оказывать никакого влияния на состояние компонентов, тогда | ||
его можно вызывать просто напрямую без использования хуков из этой библиотеки. | ||
Если же возникает потребность отслеживать статус выполнения мутирующего запроса, то | ||
для этого можно использовать хук `useAsyncOperation`: | ||
```tsx | ||
import axios from 'axios'; | ||
import { useAsyncOperation } from '@proscom/prostore-react'; | ||
function MyComponent() { | ||
const saveOp = useAsyncOperation( | ||
() => { | ||
// Чтобы корректно отследить статус завершения операции, | ||
// колбек должен возвращать промис | ||
return axios.post('/save', data).catch((e) => console.error(e)); | ||
// То, как обрабатывать ошибку следует решить на уровне конкретного проекта. | ||
// Рекомендуется отобразить пользователю toast или текст ошибки рядом с кнопкой действия. | ||
}, | ||
{ | ||
// После завершения операции ставит finished=true на 5 секунд | ||
// Передайте Infinity, чтобы поставить finished=true навсегда после первого выполнения операции | ||
finishedTimeout: 5000, | ||
// Предотвращает повторный вызов операции до завершения предыдущей | ||
singleton: true | ||
} | ||
); | ||
const { | ||
// Функция для вызова операции | ||
run, | ||
// true, если операция выполняется | ||
loading, | ||
// true, если операция недавно завершена | ||
finished, | ||
// позволяет поменять значение finished в сложных случаях | ||
setFinished | ||
} = saveOp; | ||
return ( | ||
<button onClick={run} disabled={loading}> | ||
{finished ? 'Saved' : loading ? 'Saving...' : 'Save'} | ||
</button> | ||
); | ||
} | ||
``` | ||
[См. пример в CodeSandbox](https://codesandbox.io/s/prostore-react-demo-async-operation-tzlhm) |
export * from './ProstoreContext'; | ||
export * from './ProstoreSsrContext'; | ||
export * from './useAsyncOperation'; | ||
export * from './useConnectStore'; | ||
@@ -4,0 +5,0 @@ export * from './useRequestStore'; |
@@ -14,3 +14,3 @@ import { useContext, createContext } from 'react'; | ||
*/ | ||
export const ProstoreContext = createContext<IProstoreContext>(null); | ||
export const ProstoreContext = createContext<IProstoreContext | null>(null); | ||
@@ -29,6 +29,9 @@ /** | ||
if (typeof storeOrName === 'string') { | ||
if (!context) { | ||
throw new Error(`ProstoreContext is not provided`); | ||
} | ||
const store = context[storeOrName]; | ||
if (!store) { | ||
throw new Error( | ||
`Store '${storeOrName}' is not registered in the context` | ||
`Store '${storeOrName}' is not registered in the ProstoreContext` | ||
); | ||
@@ -35,0 +38,0 @@ } |
@@ -7,3 +7,3 @@ import { createContext } from 'react'; | ||
*/ | ||
export const ProstoreSsrContext = createContext<ProstoreSsrManager>(null); | ||
export const ProstoreSsrContext = createContext<ProstoreSsrManager|null>(null); | ||
@@ -10,0 +10,0 @@ export type IStates = { |
@@ -7,3 +7,3 @@ import { IStore } from '@proscom/prostore'; | ||
*/ | ||
export function useConnectStore<State>( | ||
export function useConnectStore<State = any>( | ||
store: IStore<State>, | ||
@@ -10,0 +10,0 @@ setState: (state: State) => any |
@@ -7,7 +7,10 @@ import { BehaviorSubject, Observable } from 'rxjs'; | ||
*/ | ||
export function useObservable<State>( | ||
obs$: Observable<State>, | ||
export function useObservable<State = any>( | ||
obs$: Observable<State>|null|undefined, | ||
setState: (state: State) => any | ||
) { | ||
useEffect(() => { | ||
if (!obs$) { | ||
return; | ||
} | ||
const sub = obs$.subscribe((state: State) => { | ||
@@ -25,6 +28,13 @@ setState(state); | ||
*/ | ||
export function useObservableState<State>( | ||
obs$: Observable<State>, | ||
initialState: State = null | ||
): State { | ||
export function useObservableState<State = any>( | ||
obs$: Observable<State>|null|undefined, | ||
initialState: State | ||
): State; | ||
export function useObservableState<State = any>( | ||
obs$: Observable<State>|null|undefined | ||
): State | null; | ||
export function useObservableState<State = any>( | ||
obs$: Observable<State>|null|undefined, | ||
initialState: State | null = null | ||
): State | null { | ||
const [state, setState] = useState(initialState); | ||
@@ -38,4 +48,4 @@ useObservable(obs$, setState); | ||
*/ | ||
export function useSubject<State>(sub$: BehaviorSubject<State>) { | ||
return useObservableState(sub$, sub$.value); | ||
export function useSubject<State = any>(sub$: BehaviorSubject<State>|null|undefined) { | ||
return useObservableState(sub$, sub$?.value ?? null); | ||
} |
@@ -0,29 +1,29 @@ | ||
import { useContext, useEffect, useState } from "react"; | ||
import { | ||
DependencyList, | ||
useCallback, | ||
useContext, | ||
useEffect, | ||
useMemo, | ||
useRef, | ||
useState | ||
} from 'react'; | ||
import { | ||
CheckRequestResult, checkRequestState, | ||
CheckRequestResult, | ||
checkRequestState, | ||
CheckRequestStateFn, | ||
IRequestState, | ||
IRequestStoreOptions, | ||
RequestStore, | ||
} from '@proscom/prostore'; | ||
import { useConnectStore } from './useConnectStore'; | ||
import { useContextStore } from './ProstoreContext'; | ||
import { ProstoreSsrContext } from './ProstoreSsrContext'; | ||
GetRequestStoreData, | ||
GetRequestStoreOptions, | ||
GetRequestStoreState, | ||
GetRequestStoreVars, | ||
RequestStore | ||
} from "@proscom/prostore"; | ||
import { useLatestCallbackRef } from "@proscom/ui-react"; | ||
import { useConnectStore } from "./useConnectStore"; | ||
import { useContextStore } from "./ProstoreContext"; | ||
import { ProstoreSsrContext } from "./ProstoreSsrContext"; | ||
export interface UseRequestStoreResult<Vars, Data, Options> { | ||
export interface UseRequestStoreResult<Store extends RequestStore> { | ||
check: CheckRequestResult; | ||
state: IRequestState<Vars, Data>; | ||
load: (options?: Options) => Promise<IRequestState<Vars, Data>>; | ||
store: RequestStore<Vars, Data, Options>; | ||
state: GetRequestStoreState<Store>; | ||
load: ( | ||
options?: GetRequestStoreOptions<Store> | ||
) => Promise< | ||
GetRequestStoreState<Store> | ||
>; | ||
store: Store; | ||
} | ||
export interface UseRequestOptions<Vars, Data> { | ||
export interface UseRequestOptions<Vars = any, Data = any> { | ||
checkRequest?: CheckRequestStateFn<Vars, Data>; | ||
@@ -33,3 +33,3 @@ } | ||
/** | ||
* Attached component to the provided store and requests data based on the variables and options | ||
* Attaches component to the provided store and requests data based on the variables and options | ||
* | ||
@@ -43,19 +43,18 @@ * @param storeOrName - RequestStore to subscribe to, or its name for it to be injected from the context | ||
*/ | ||
export function useRequestStore< | ||
Vars, | ||
Data, | ||
Options extends IRequestStoreOptions<Vars, Data> | ||
>( | ||
storeOrName: string | RequestStore<Vars, Data, Options>, | ||
variables: Vars, | ||
options: Options = undefined, | ||
hookOptions: UseRequestOptions<Vars, Data> = {} | ||
): UseRequestStoreResult<Vars, Data, Options> { | ||
export function useRequestStore<Store extends RequestStore>( | ||
storeOrName: string | Store, | ||
variables: GetRequestStoreVars<Store> | undefined = undefined, | ||
options: GetRequestStoreOptions<Store> | undefined = undefined, | ||
hookOptions: UseRequestOptions< | ||
GetRequestStoreVars<Store>, | ||
GetRequestStoreData<Store> | ||
> = {} | ||
): UseRequestStoreResult<Store> { | ||
const checkRequest = hookOptions.checkRequest || checkRequestState; | ||
// Inject store from context | ||
const store = useContextStore<RequestStore<Vars, Data, Options>>(storeOrName); | ||
const store = useContextStore<Store>(storeOrName); | ||
// Local copy of store state | ||
const [state, setState] = useState(store.state); | ||
const [state, setState] = useState<GetRequestStoreState<Store>>(store.state); | ||
@@ -69,11 +68,7 @@ // Subscribe to store changes | ||
// Memoized callback to request data | ||
const funcsRef = useRef<{ | ||
loadData?: UseRequestStoreResult<Vars, Data, Options>['load']; | ||
}>({}); | ||
funcsRef.current.loadData = (newOptions = undefined) => { | ||
return store.loadData(variables, newOptions || options); | ||
}; | ||
const loadData = useCallback((newOptions = undefined) => { | ||
return funcsRef.current.loadData(newOptions); | ||
}, []); | ||
const loadData = useLatestCallbackRef( | ||
(newOptions: GetRequestStoreOptions<Store> | undefined = undefined) => { | ||
return store.loadData(variables, newOptions || options); | ||
} | ||
); | ||
@@ -101,21 +96,1 @@ // Request the data if it is should be requested | ||
} | ||
/** | ||
* The same as useRequestStore, but it uses variableCreator which is supplied to useMemo and | ||
* can be used to memoize query variables. This may be used when the default behavior of deeply | ||
* comparing variables is not preferable (i.e., it is not fast enough, or variables are not simple objects) | ||
* | ||
* @returns {{load, check, state}} - Current request state | ||
*/ | ||
export function useRequestStoreVars< | ||
Vars, | ||
Data, | ||
Options extends IRequestStoreOptions<Vars, Data> | ||
>( | ||
storeOrName: string | RequestStore<Vars, Data, Options>, | ||
variableCreator: () => Vars, | ||
args: DependencyList | ||
) { | ||
const variables = useMemo(variableCreator, args); | ||
return useRequestStore(storeOrName, variables); | ||
} |
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
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
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
97108
70
1554
356
4
+ Added@proscom/ui-react@^0.0.6
+ Added@proscom/prostore@0.2.12(transitive)
+ Added@proscom/ui-react@0.0.6(transitive)
+ Added@proscom/ui-utils@0.0.60.1.18(transitive)
+ Addedasync@3.2.6(transitive)
+ Addedlodash-es@4.17.21(transitive)
+ Addedts-custom-error@3.3.1(transitive)
- Removed@proscom/prostore@0.1.13(transitive)
Updated@proscom/prostore@^0.2.0