@browser-search/react-browser-search v1.0.0
react-browser-search
-> Take a look at the demo
This library provides react hooks to the browser-search library Please read the documentation of browser-search before using
- Get Started - Installation - Usage flow
- API Methods - useCreateStore - Signature - Example - useAddDocumentsToStore - Signature - Example - useQuery - Signature - Example - useIndexValues - Signature - Example - useDeleteStore - Signature - Example - BrowserSearchProvider - Example
- API Interfaces - QueryState - Definition
Get Started
Installation
Yarn
yarn add @browser-search/browser-search
yarn add @browser-search/react-browser-search
Npm
npm install -S @browser-search/browser-search
npm install -S @browser-search/react-browser-search
Usage flow
graph LR
0[Wrap components with provider]--> A
A[Create document store]--> B[Add Documents]
B --> C[Run a query]
B --> E[etc.]
Step 1 - Wrap your component tree in the react-browser-search provider
For the hooks to work, you need to wrap your component tree in the provider which contains a client + cache layer. See BrowserSearchProvider for usage
Step 2 - Create a store
To get started, create a store that will later hold your data. You need to know in advance
- the type of the documents you will store
- the fields that you will use for filtering / sorting. Those fields must be indexed. See useCreateStore
Step 3 - Add documents
Then you can add documents to the newly created store See useAddDocumentsToStore
Step 4 - run a search query
You can now run complex queries to filter and sort your document, and display them to your users. See useQuery for usage
API Methods
useCreateStore
Signature
<TDocument>(): [(request: CreateStoreRequest<TDocument>) => Promise<void>, QueryState<TDocument>]
Generics
TDocument
is the type of the document you will store
Parameters
none
Return value
[(request: CreateStoreRequest<TDocument>) => Promise<void>, QueryState<TDocument>]
With
request: CreateStoreRequest<TDocument>
is the object containing the request for the store creation -storeId: string
the name of the store to create -indexConfig: SimplifiedIndexConfig<DataSchema>
the fields to index. see reference here -keyPath: keyof TDocument
is the field which is be the primary key. That field does not need to be included in theindexConfig
abovequeryState: UseCreateStoreQueryState
: see QueryState
Example
Let's say we want to store books of the following type:
export interface Book {
isbn: string; // primary key
title: string;
releaseDate: string;
authors: string[];
categories: Array<'fantasy' | 'sci-fi' | 'thriller'>;
description: string;
}
We want to be able to filter and sort on every field but the description.
import { SimplifiedIndexConfig } from '@browser-search/browser-search';
import { useCreateStore, UseCreateStoreQueryState } from '@browser-search/react-browser-search';
const storeName = "bookLibrary";
const indexConfig: SimplifiedIndexConfig<Book> = {
simple: ['title', 'releaseDate'],
array: ['authors', 'categories'],
};
const keyPath = 'isbn';
const useCreateLibraryStore = (): [() => Promise<void>, UseCreateStoreQueryState<Book>] => {
const [createStore, createStoreQueryState] = useCreateStore<Book>();
const createLibraryStore = () => createStore({
storeId,
indexConfig,
keyPath,
});
return [createPersonStore, createStoreQueryState];
};
useAddDocumentsToStore
Signature
<TDocument>(): [(request: AddDocumentsToStoreRequest<TDocument>) => Promise<void>, QueryState<TDocument>]
Generics
TDocument
is the type of the document you will store
Parameters
none
Return value
[(request: AddDocumentsToStoreRequest<TDocument>) => Promise<void>, QueryState<TDocument>]
With
request: AddDocumentsToStoreRequest<TDocument>
is the object containing the request to add the data to the store -storeId: string
the name of the store to create -documents: TDocument[]
is the array of documents to be storedqueryState: UseAddDocumentsToStoreQueryState
: see QueryState
Example
import { useAddDocumentsToStore, UseAddDocumentsToStoreQueryState } from '@browser-search/react-browser-search';
const storeId = 'bookLibrary';
const useAddBooksToLibraryStore = (): [(books: Book[]) => Promise<void>, UseAddDocumentsToStoreQueryState<Book>] => {
const [addDocumentsToStore, addDocumentsToStoreQueryState] = useAddDocumentsToStore<Person>();
const addBooksToLibraryStore = (books: Book[]) => {
return addDataToStore({
storeId,
documents: books
})
}
return [addBooksToLibraryStore, addDocumentsToStoreQueryState];
}
useQuery
Hook behaviour:
- Every query response is cached
- The cache is automatically invalidated at any store mutation and the request is automatically re-triggered
- A request automatically cancels a previously pending request
Signature
<TDocument, TFilterId extends string = string>(request: QueryRequest<TDocument, TFilterId>): QueryState<TDocument, TFilterId>
Generics
TDocument
is the type of the document you will storeTFilterId
is the string union of all the filters ids defined in the filterConfiguration object, passed in the request. Defaults to a string.
Parameters
request: QueryRequest<TDocument, TFilterId>
is the object containing the query parameters. Refer to QueryRequest
Return value
UseQueryQueryState<TDocument, TFilterId>
see QueryState
Example
import { useQuery, UseQueryQueryState } from '@browser-search/react-browser-search';
import { QueryRequest, FilterConfig } from '@browser-search/browser-search';
type FilterIds = 'categoryFantasy' | 'categorySciFi' | 'categoryThriller';
const storeId = 'bookLibrary';
export const useBookQuery = (filterApplied: FilterIds[]): UseQueryQueryState<Book, FilterId> => {
const filterConfig: FilterConfig<Book, FilterIds> =
[
[
{ id: 'categoryFantasy', field: 'categories', operator: 'contains', operand: 'fantasy' },
{ id: 'categorySciFi', field: 'categories', operator: 'contains', operand: 'sci-fi' },
{ id: 'categoryThriller', field: 'categories', operator: 'contains', operand: 'thriller' },
],
];
const queryRequest: QueryRequest<Person, FilterId> = () => (
storeId,
filterConfig,
filtersApplied, // the ids of the filter in the filter configuration that you are filtering on. Example: ['categoryFantasy', 'categorySciFi']
orderBy: 'releaseDate',
orderDirection: 'DESC',
perPage: 10,
page: 0,
};
return useQuery<Book, FilterId>(queryRequest);
}
useIndexValues
Hook behaviour:
- Every query response is cached.
- The cache is automatically invalidated on any store mutation and the request is automatically re-triggered
Signature
<T extends IDBValidKey>({storeId, field}: GetIndexValuesRequest): QueryState<T>
Generics
T
is the type of the property indexed, that should be compliant with theIDBValidKey
interface, whereIDBValidKey = number | string | Date | BufferSource | IDBValidKey[]
Parameters
request: GetIndexValuesRequest
is the object containing the request parameters. -storeId: string
: the store name -field: string
is the property for which you want to get all the values. It should be indexed at the store creation. See SimplifiedIndexConfig reference
Return value
UseIndexValuesQueryState<T>
see QueryState
Example
import { useIndexValues, UseIndexValuesQueryState } from '@browser-search/react-browser-search';
const storeId = 'bookLibrary';
// to get the list of all the titles stored
export const useBookTitleValues = (): UseIndexValuesQueryState<string> => {
return useIndexValues<string>({
storedId,
field: 'title',
});
}
useDeleteStore
Signature
(): [(request: DeleteStoreRequest) => Promise<void>, QueryState]
Parameters
none
Return value
[(request: DeleteStoreRequest) => Promise<void>, QueryState]
With
request: DeleteStoreRequest
is the object containing the request for the store deletion -storeId: string
the name of the store to createqueryState: UseDeleteStoreQueryState
: see QueryState
Example
import { useDeleteStore, UseDeleteStoreQueryState } from '@browser-search/react-browser-search';
const useDeleteLibraryStore = (): [() => Promise<void>, UseDeleteStoreQueryState] => {
const [deleteStore, deleteStoreQueryState] = useDeleteStore();
const deleteLibraryStore = () => deleteStore({
storeId: "bookLibrary",
});
return [deleteLibraryStore, deleteStoreQueryState];
};
BrowserSearchProvider
This react component connects your tree to the browser-search context
- any component calling a browser-search hook should be a child of this one
Example
import { BrowserSearchProvider } from '@browser-search/react-browser-search';
<BrowserSearchProvider>
<App />
</BrowserSearchProvider>
API Interfaces
QueryState
This interface is returned by every hook. It is a react-state (meaning your component will re-render each time the query state changes) that represents the progress of the request.
QueryState
is a union type that can take the following shape:
IdleQueryState | LoadingQueryState | SuccessQueryState | StaleQueryState | ErrorQueryState
IdleQueryState
: when the request is not started. Example: a store mutation not yet called.LoadingQueryState
: when the request is ongoing. React-state equivalent of a pending promise.SuccessQueryState
: when the request has succeeded. React-state equivalent of a resolved promise.StaleQueryState
: when a new request is loading after a previous one succeeded. Only returned for non-mutation hooks, ie. only for useIndexValues and useQuery. This state is useful when you still need access to the stale data while the new request is loading.ErrorQueryState
: when the request failed. React-state equivalent of a rejected promise.
graph LR
0[IdleQueryState]-->A
A[LoadingQueryState]--> B[SuccessQueryState]
A --> C[ErrorQueryState]
B --> D[StaleQueryState]
D --> B
D --> C
Definition
interface IdleQueryState {
status: 'idle';
isFetching: false;
}
interface LoadingQueryState<Request> {
status: 'loading';
request: Request;
isFetching: true;
}
interface SuccessQueryState<Request, Response> {
status: 'success';
request: Request;
response: Response;
isFetching: false;
}
interface StaleQueryState<Request, Response> {
status: 'stale';
request: Request;
response: Response;
newRequest: Request;
isFetching: true;
}
interface ErrorQueryState<Request, Error>
status: 'error';
request: Request;
error: Error;
isFetching: false;
}
type QueryState<Request, Response, Error> = IdleQueryState | LoadingQueryState<Request> | SuccessQueryState<Request, Response> | StaleQueryState<Request, Response> | ErrorQueryState<Request, Error>;