Coder Social home page Coder Social logo

lucaong / react-minisearch Goto Github PK

View Code? Open in Web Editor NEW
38.0 6.0 7.0 1.67 MB

React integration for the MiniSearch client side full-text search library

License: MIT License

TypeScript 97.15% JavaScript 2.85%
react full-text search autosuggestion autocomplete search-engine minisearch

react-minisearch's Introduction

React MiniSearch

React integration for the MiniSearch client side full-text search library.

Getting Started

Installation:

First, make sure you have a compatible version of React and of MiniSearch installed.

Then, install via NPM or Yarn:

# With NPM:
npm install react-minisearch

# Or with Yarn:
yarn add react-minisearch

Usage:

There are three main ways to use react-minisearch: the useMiniSearch hook, the withMiniSearch higher-order component, or the WithMiniSearch wrapper component.

All three way take the following arguments (or props for the wrapper component):

  • The initial collection of documents to add to the index. Note: this is just the initial collection, and mutating this argument won't cause reindexing. To add or remove documents after initialization, use the functions add/addAll/remove/removeAll/discard, etc.
  • The MiniSearch configuration options

Using the useMiniSearch hook:

import { useMiniSearch } from 'react-minisearch'

// Documents to search amongst
const documents = [
  { id: 1, name: 'Agata' },
  { id: 2, name: 'Finn' },
  // …etc
]

// See MiniSearch for documentation on options
const miniSearchOptions = { fields: ['name'] }

const MyComponent = () => {
  const { search, searchResults } = useMiniSearch(documents, miniSearchOptions)

  const handleSearchChange = (event) => {
    search(event.target.value)
  }

  return (
    <div>
      <input type='text' onChange={handleSearchChange} placeholder='Search…' />

      <ol>
        <h3>Results:</h3>
        {
          searchResults && searchResults.map((result, i) => {
            return <li key={i}>{ result.name }</li>
          })
        }
      </ol>
    </div>
  )
}

Using the withMiniSearch higher-order component:

import { withMiniSearch } from 'react-minisearch'

const MyComponent = ({ search, searchResults }) => {

  const handleSearchChange = (event) => {
    search(event.target.value)
  }

  return (
    <div>
      <input type='text' onChange={handleSearchChange} placeholder='Search…' />

      <ol>
        <h3>Results:</h3>
        {
          searchResults && searchResults.map((result, i) => {
            return <li key={i}>{ result.name }</li>
          })
        }
      </ol>
    </div>
  )
}

// Documents to search amongst
const documents = [
  { id: 1, name: 'Agata' },
  { id: 2, name: 'Finn' },
  // …etc
]

// See MiniSearch for documentation on options
const miniSearchOptions = { fields: ['name'] }

const MyComponentWithSearch = withSearch(documents, miniSearchOptions, MyComponent)

Using the WithMiniSearch wrapper component:

import { WithMiniSearch } from 'react-minisearch'

// Documents to search amongst
const documents = [
  { id: 1, name: 'Agata' },
  { id: 2, name: 'Finn' },
  // …etc
]

// See MiniSearch for documentation on options
const miniSearchOptions = { fields: ['name'] }

const MyComponent = () => (
  <WithMiniSearch documents={documents} options={miniSearchOptions}>
    {
      ({ search, searchResults }) => {
        const handleSearchChange = (event) => {
          search(event.target.value)
        }

        return (
          <div>
            <input type='text' onChange={handleSearchChange} placeholder='Search…' />

            <ol>
              <h3>Results:</h3>
              {
                searchResults && searchResults.map((result, i) => {
                  return <li key={i}>{ result.name }</li>
                })
              }
            </ol>
          </div>
        )
      }
    }
  </WithMiniSearch>
)

Provided props:

The complete set of props that are provided by react-minisearch is the same for all three ways (useMiniSearch, withMiniSearch, or WithMiniSearch):

  • search(query: string, searchOptions?: SearchOptions) => void: function to be called in order to perform the search

  • searchResults: T[] | null: array of search results, or null when no search was performed or search was cleared

  • rawResults: SearchResult[] | null: array of raw search results from MiniSearch, including scores and match information, or null when no search was performed or search was cleared

  • clearSearch() => void: function to be called in order to clear the search (setting searchResults to null)

  • autoSuggest(query: string, searchOptions?: SearchOptions) => void: function to be called in order to obtain auto suggestions

  • suggestions: Suggestion[] | null: array of auto suggestions, or null when auto suggestions are not used or cleared

  • clearSuggestions() => void: function to be called in order to clear the suggestions (setting suggestions to null)

  • add(document: T) => void: function to add a new document to the index

  • addAll(documents: T[]) => void: function to add several new documents to the index in bulk

  • addAllAsync(documents: T[], options?: object) => Promise<void>: same as addAll, but works asynchronously and in batches to avoid blocking the UI

  • remove(document: T) => void: function to remove a document from the index

  • removeById(id: any) => void: function to remove a document from the index by its ID

  • removeAll(documents?: T[]) => void: function to remove several documents, or all documents, from the index

  • discard(id: any) => void: discard a document by its ID (same as removeById)

  • discardAll(ids: readonly any[]) => void: discard several documents at once, by their ID

  • replace(document: T) => void: replace an existing document with a new version of it

  • isIndexing: boolean: set to true when indexing via addAllAsync is in progress, false otherwise

  • miniSearch: MiniSearch: the MiniSearch instance, for the (rare) cases when it is necessary to use it directly

In this list, the type T is a generic type that refers to the type of the document being indexed.

Many of these props correspond to methods on the MiniSearch class, as documented in the MiniSearch library.

Examples

Check out the examples directory for a complete usage example. To run the example app locally:

  • cd to the examples directory
  • Install dependencies with yarn install (or npm install)
  • Run the example application with yarn start (or npm run start)

react-minisearch's People

Contributors

alessandrobardini avatar dependabot[bot] avatar happycollision avatar lucaong avatar neezurft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

react-minisearch's Issues

License?

Hi Luca,

Could you add a license to this repo? great work on minisearch.

React-Minisearch: Argument of type 'IUserDisplayInfo[]' is not assignable to parameter of type 'readonly never[]'.

Explain the bug

I am trying to fetch data from firestore using the firebase sdk and useQuery from Tanstack-Query, but when I try to index it to react-minisearch it throws a type error (the error is down below).

I am completely new to tsc and I'm trying to migrate my js react app into tsc.

Code

The useQuery hook that fetches data from getPublicData and indexes it to react-minisearch:

  const { data: setsData } = useQuery<ILibraryCard[]>({
    queryKey: ["publicSets"],
    queryFn: async () => {
      const data: ILibraryCard[] = await getPublicSets();
      await addAllAsync(data);
      return data;
    },
    refetchOnWindowFocus: false,
  });

data in addAllSync throws error

Argument of type 'IUserDisplayInfo[]' is not assignable to parameter of type 'readonly never[]'.
Type 'IUserDisplayInfo' is not assignable to type 'never'.ts(2345)

My getPublicData hook:

export const getPublicSets = async (): Promise<ILibraryCard[]> => {
  const docsQuery = query(
    collection(firestore, "studySets"),
    where("isPublic", "==", true)
  );
  const arr: ILibraryCard[] = [];
  const docsSnap = await getDocs(docsQuery);
  docsSnap.forEach((doc) => {
    const data = doc.data();
    arr.push({
      title: data.head.title,
      description: data.head.description,
      id: doc.id,
      creator: data.creator,
    });
  });
  return arr;
};

Interface:


export interface ILibraryCard {
  title: string;
  description: string;
  id: string;
  creator: string;
}

Any help would be much appreciated :)

If this issue is missing something critical related to the issue, please let me know so that I can provide any additional information since this is my very first issue that I've made.

using `MiniSearch.wildcard` throws an error

Hi, @lucaong ! First, thanks for this amazing project, it's been a real pleasure working with this library!!!

I'm trying to use search(MiniSearch.wildcard) but for some reason doing so throws an error in the MiniSeach package. It looks like this check isn't working
https://github.com/lucaong/minisearch/blob/4fc49a43400b3dbce9f029f4c4a836ae56311928/src/MiniSearch.ts#L1489

And, so the next check is actually being triggered
https://github.com/lucaong/minisearch/blob/4fc49a43400b3dbce9f029f4c4a836ae56311928/src/MiniSearch.ts#L1493C27-L1493C27

and fails when trying to map the queries which don't exist on the wildcard Symbol
https://github.com/lucaong/minisearch/blob/4fc49a43400b3dbce9f029f4c4a836ae56311928/src/MiniSearch.ts#L1495
I wonder if the widlcard symbol isn't recognized because it's coming from another "import" of the MiniSearch package?

// the import that executes the query
import { useMiniSearch } from 'react-minisearch'
// the import where MiniSearch.wildcard comes from
import MiniSearch from 'minisearch'

Loading indicator

I have a large batch of documents to index (tens of megabytes), is there a way to await the indexing operation? (I am using the hook)

Uncaught TypeError: MiniSearch__default.default is not a constructor

Hello, i'm caused by "Uncaught TypeError: MiniSearch__default.default is not a constructor"
when just trying to initialize const { search, searchResults } = useMiniSearch(documents, miniSearchOptions)
doing same as provided in examples.
May be i'm doing wrong?
p.s. sorry for my english

`useMiniSearch` breaks Vite build

There seems to be an issue with the way that useMiniSearch is including MiniSearch in production builds.

Reproduction here:
https://stackblitz.com/edit/vitejs-vite-j8sehn

In that reproduction you'll see in the console there is the following error (after it is done building):

u.default.getDefault is not a function

Which is specifically referring to:

var idField = options.idField || MiniSearch__default["default"].getDefault('idField');

If I update the minisearch options to include idField and extractField, it works fine:

import minisearch from 'minisearch'

const options: SearchOptions<SearchItem> = {
  fields: ['name', 'email'],
  storeFields: ['id'],
  searchOptions: {
    fuzzy: true,
    prefix: true,
  },

  // fixes build error
  idField: 'id',
  extractField: minisearch.getDefault('extractField'),
}

This is a fine stop gap solution, but it may be worth investigating why this is not working with Vite. I'm assuming it's due to Vite being an esm based bundler.

React Mini-search stalls on unmount for large collections

Hi, amazing library! I've been using it on many different projects, and it has always worked well. I recently introduced a much larger document collection to my application (about 37,000 fairly unique documents) and I've been encountering a performance problem with the cleanup introduced in c846552 related to these lines:

return () => {
utils.removeAll(documents)
}

When my search UI unmounts, it causes a long blocking stall (about 1 second).

Here's the performance trace:

Chrome performance trace

Technically, I can manage my own document collection and supply [] as the documents parameter to skip over all of this, but I thought it would be good to raise this.

Current master is not working [a23e198]

Hello there @lucaong,

I was recently used the minisearch hook you did here and preparing for a PR for improvement. But I stuck on failing master.
Here is what I did:

  • Clone the react-minisearch repo on my local, install the deps and build it (yarn install && yarn build)
  • navigate the examples folders.
  • change the react-minisearch deps from "^2.1.4" to "file:../"
  • install the examples deps then started it (yarn install && yarn start)
  • BOOM!

Here is the full output of my browser's dev tools console

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (webpack-internal:///./node_modules/react-minisearch/node_modules/react/cjs/react.development.js:1465)
    at Object.useState (webpack-internal:///./node_modules/react-minisearch/node_modules/react/cjs/react.development.js:1496)
    at useMiniSearch (webpack-internal:///./node_modules/react-minisearch/dist/react-minisearch.js:38)
    at App (webpack-internal:///./src/app.jsx:46)
    at renderWithHooks (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:14803)
    at mountIndeterminateComponent (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:17482)
    at beginWork (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:18596)
    at HTMLUnknownElement.callCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:237)
    at invokeGuardedCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:292)
webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:19527 The above error occurred in the <App> component:
    in App (created by WithDocuments)
    in WithDocuments

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
logCapturedError @ webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:19527
webpack-internal:///./node_modules/react-minisearch/node_modules/react/cjs/react.development.js:1465 Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (webpack-internal:///./node_modules/react-minisearch/node_modules/react/cjs/react.development.js:1465)
    at Object.useState (webpack-internal:///./node_modules/react-minisearch/node_modules/react/cjs/react.development.js:1496)
    at useMiniSearch (webpack-internal:///./node_modules/react-minisearch/dist/react-minisearch.js:38)
    at App (webpack-internal:///./src/app.jsx:46)
    at renderWithHooks (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:14803)
    at mountIndeterminateComponent (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:17482)
    at beginWork (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:18596)
    at HTMLUnknownElement.callCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:237)
    at invokeGuardedCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:292)

I still wish to make my improvement PR once fixing this error. I am hoping you might leave some clue why is the error happening. And I gladly introduce a PR to fix it.

Allow passing pre-built search index to useMiniSearch

As we discussed in an issue in the main MiniSearch repo, in some use cases it makes sense to pre-build a search index, so that one can provide and load this index. However, the useMiniSearch hook only allows providing an array of documents currently.

I concede that this is not necessarily a common use case, and my team and I can work around it easily, so don't feel obligated to push this out in a hurry - I just wanted to leave an issue for future reference 🙂

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.