In this article, the step-by-step instruction of creating your own autocomplete input component using AsyncResolver , StateProvider and DebouncePropagator from reenhance-components . You can find CodePen and example repository at the bottom.

A short background

Modern web applications have various interactive components. The most commonly used one will be autocomplete inputs which help users input values quickly and correctly. Typically, those suggestions are coming from backend APIs like product database, sales ranking, user’s history or some other big-data.

Making such components with React was not very easy because it is full of async, events and state management. Now it became much easier with reenhance-components . The resulting component of this article looks like this.

Let’s proceed to next step.

Managing Input state

In React, the value of input field should be stored in some state. Otherwise, you will need a ref object to get the value from DOM attribute. The most common way is called controlled components.

Although the state can be stored in Redux but it’s not always a good idea. In my opinion, the state can be stored locally if the field is used only for filtering or query values. To create local store declaratively in JSX, StateProvider from reenhance-components can be used as shown here:

const InputState = StateProvider(''); const SuggestedInput = () => (

<InputState>

{({ state: query, setState: setQuery }) => (

<div>

<input value={query} onChange={e => setQuery(e.target.value)} />

</div>

)}

</InputState>

);

Performing API request

To get suggestions from backend system, calling fetch API (or similar) is necessary. Those APIs return Promise so they must be resolved before rendering contents.

In my former article, I showed an example using RxJS and HoCs but now a wrapping component, AsyncResolver is available. With AsyncResolver , you can retrieve response contents just by passing an async function and parameters as props in JSX. Here is the example:

const asyncFetch =

({ query }) =>

fetch(queryToUrl(query))

.then(res => res.json()); const SuggestAsyncResolver = AsyncResolver('query', []); const Suggests = ({ query }) => (

<SuggestAsyncResolver query={query} subject={asyncFetch}>

{props => (

<ul>

{props[1].map(str => (

<li key={str}>{str}</li>

))}

</ul>

)}

</SuggestAsyncResolver>

);

Reducing API requests by debounce

In real applications, it’s very important to reduce API requests from end-users. For autocomplete, we can retard API request by 150–200ms without any degradation in user experience.

However, just delaying isn’t good enough but have to consolidate events within that duration. Such behavior is called debounce in RxJS.

The figure of debounce from RxJS document

It can be adopted using DebouncePropagator which delays a prop propagation in JSX for given milliseconds.

The example:

const SuggestDebounce = DebouncePropagator({ query: '' }); const SuggestsWithDebounce = ({ query }) => (

<SuggestDebounce time={200} query={query}>

{({ query }) => (

<div>

<Suggests query={query} />

</div>

)}

</SuggestDebounce>

)

The resulting product

You can try this example in CodePen. It shows suggestions from Amazon.com.

And also, here’s a repository using WebPack and Babel. Simply checkout and type npm install and npm start to try it locally.

Conclusion