@lindeneg/search

Hook for filtering and optionally sorting objects against a query.

Usage no npm install needed!

<script type="module">
  import lindenegSearch from 'https://cdn.skypack.dev/@lindeneg/search';
</script>

README

@lindeneg/search

typescript bundle-size license

Sandbox


React hook for filtering and optionally sorting objects by nested values against a query in a type-safe way.

Installation

yarn add @lindeneg/search


Arguments

Name Required Ref Type Description
data Y T Array<Record<string \| number \| symbol, unknown>> array of objects to filter
predicate Y - string[] \| (query: string, item: T[number], index: number) => boolean an array of property names to target or a predicate function
opts N - UseSearchOptions options, see below

UseSearchOptions

Name Required Default Type Description
mode N "lenient" "strict" \| "lenient" lenient escapes invalid symbols, strict ignores them completely
sort N - (a: T[number], b: T[number]) => number optionally provide a sort function to be called post-filtering

Return

Object with properties:

Name Type Description
filtered T array of filtered, optionally sorted, objects
query string the current query
onQueryChange (target: string \| React.FormEvent<HTMLInputElement>) => void; function to change query
onPredicateChange (predicate: string[] \| (query: string, item: T[number], index: number) => boolean) => void; function to change predicate

Usage

import useSearch from '@lindeneg/search';

function SomeComponent() {
  const { filtered, query, onQueryChange, onPredicateChange } = useSearch(
    data,
    predicate,
    useSearchOptions
  );

  console.log(filtered);

  return (
    <div>
      <input value={query} onChange={onQueryChange} />
    </div>
  );
}

Suppose the following object:

interface User {
  id: number;
  name: string;
  email?: string;
  activity: { events: { context: string }[] }[];
  interest: {
    name: string;
    info: {
      special: string;
    };
  };
  arr: string[];
}

Say the interesting keys when filtering are name and email:

useSearch(users, ['name', 'email']);

Then the data will be filtered using the values of the name and email keys against a query.

Values found inside nested objects or arrays can also be used. Suppose the desired key to include is context found inside the events array that is itself found inside the activity array.

useSearch(users, ['activity.n.events.n.context']);

Then the data will be filtered using the values of the context key against a query. n is used to describe that the current key is an index value, all items in the array will be considered.

Decent type-safety is also achieved, as can be seen in this example:

the search depth is 5 layers, so x.y.z.i.j will be inferred while x.y.z.i.j.k will not

use-search-type-safety