# Debounce and persist event targeting in react

By [Server Surfer](https://paragraph.com/@serversurfer) · 2021-11-18

---

Recently I worked on a search component that would communicate with an API that uses ElasticSearch for indexing. It's common to have a search input, that as you type will auto query and update the list on the frontend.

So I used a text input, and inside the \`onChange\` event would pass the \`event.target.value\` as a parameter to the API url.

It would look something like this (abbreviated for readability):

    const searchQueryFunction = (queryText) => {
    
        const res = await fetch(`/products.json?_page=${page}&_limit=10&_q=${queryText}&_total=50`, {
        method: 'GET',
        headers: {
         'Access-Control-Allow-Origin': '*'
        }
      })
    
      const responseData = await res.json()
    
      setItems({items: responseData.data})
    }
    
    <input type="text" placeholder="Search..." onChange=((e) => searchQueryFunction(e.target.value)) />
    

But I quickly found out how taxing this was for the browser and server. As I would search for something like "Minivan", it would query each letter. This is where a debouncer comes in. There are libraries like \`lodash\` that offer a function, but wanted to keep my \`package.json\` light.

A debouncer is just a fancy \`setTimeout\`, so I created a \`Debouncer\` class that takes 2 parameters. A function and time.

It looks like this:

    export default class Debouncer {
      timeout: null | ReturnType<typeof setTimeout>
      n: number
      func: Function
    
      constructor(func, n) {
        this.timeout = null
        this.n = n || 500
        this.func = func
      }
    
      execute = (e) => {
        this.cancel()
        this.timeout = setTimeout(() => {
          this.func(e)
        }, this.n)
      }
    
      cancel = () => {
        if (this.timeout) clearTimeout(this.timeout)
      }
    }
    

Inside the React component, initialize the Debouncer and pass it the `searchQueryFunction`

    const debouncer = new Debouncer((e) => searchQueryFunction(e))
    

Then create a new function that will execute the `searchQueryFunction` through the debouncer

    const execDebouncer = (e) => debouncer.execute(e)
    

Now inside the input `onChange` event, well replace calling the `searchQueryFunction` directly and use the new `execDebouncer`

    <input type="text" onChange={(e) => execDebouncer(e)} />
    

But.. you'll notice some errors in the log:

> "This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the method currentTarget on a released/nullified synthetic event. This is a no-op function. If you must keep the original synthetic event around, use event.persist()"

This is because the event is lost, while the function is being debounced for 500ms. To fix this, simply add `e.persist()` inside the `execDebouncer` function

    const execDebouncer = (e) => {
      e.persist()
      return debouncer.execute(e)
    }
    

I put together a little example, with an included mock api:

[https://codesandbox.io/embed/pensive-swartz-cvsx1](https://codesandbox.io/embed/pensive-swartz-cvsx1)

---

*Originally published on [Server Surfer](https://paragraph.com/@serversurfer/debounce-and-persist-event-targeting-in-react)*
