diff --git a/.obsidian/app.json b/.obsidian/app.json index 53ef0f2..9897fad 100644 --- a/.obsidian/app.json +++ b/.obsidian/app.json @@ -3,7 +3,7 @@ "showLineNumber": true, "tabSize": 2, "vimMode": true, - "newFileLocation": "folder", + "newFileLocation": "current", "alwaysUpdateLinks": true, "useMarkdownLinks": true, "showUnsupportedFiles": true, diff --git a/.obsidian/graph.json b/.obsidian/graph.json index f776811..114d1a6 100644 --- a/.obsidian/graph.json +++ b/.obsidian/graph.json @@ -17,6 +17,6 @@ "repelStrength": 10, "linkStrength": 1, "linkDistance": 250, - "scale": 0.4952113402093565, + "scale": 0.3580284794893512, "close": true } \ No newline at end of file diff --git a/.obsidian/plugins/obsidian-omnivore/data.json b/.obsidian/plugins/obsidian-omnivore/data.json index 0a75cee..f1d45f3 100644 --- a/.obsidian/plugins/obsidian-omnivore/data.json +++ b/.obsidian/plugins/obsidian-omnivore/data.json @@ -3,7 +3,7 @@ "dateSavedFormat": "yyyy-MM-dd HH:mm:ss", "apiKey": "ec3bba50-4770-471b-99b1-9953ca523d8c", "filter": "ADVANCED", - "syncAt": "2024-02-17T17:22:18", + "syncAt": "2024-02-20T12:01:36", "customQuery": "in:archive has:highlights", "template": "# {{{title}}}\n\n{{# note }}\n## Notes\n\n{{{ note }}}\n{{/ note }}\n{{#highlights.length}}\n## Highlights\n\n{{#highlights}}\n{{{text}}} \n{{#note}}\n\n> [!note]\n> {{{note}}}\n{{/note}}\n\n[source]({{{highlightUrl}}}) {{#labels}} #{{name}} {{/labels}}\n\n---\n\n{{/highlights}}\n{{/highlights.length}}\n## Original\n\n{{{ content }}}", "highlightOrder": "LOCATION", @@ -17,7 +17,7 @@ "version": "1.6.3", "isSingleFile": false, "frequency": 60, - "intervalId": 13, + "intervalId": 14, "frontMatterVariables": [], "frontMatterTemplate": "id: {{{ id }}}\ntitle: >\n {{{ title }}}\nstatus: {{{ state }}}\ntags:\n - read-later\n{{#labels.length}}\n{{#labels}} - {{{name}}}\n{{/labels}}\n{{/labels.length}}\ndate_added: {{{ dateSaved}}}\nurl_omnivore: >\n {{{ omnivoreUrl}}}\nurl_original: >\n {{{ originalUrl}}}" } \ No newline at end of file diff --git a/.obsidian/plugins/update-time-on-edit/data.json b/.obsidian/plugins/update-time-on-edit/data.json index 3f6fac8..b3dd672 100644 --- a/.obsidian/plugins/update-time-on-edit/data.json +++ b/.obsidian/plugins/update-time-on-edit/data.json @@ -18,21 +18,16 @@ "notes/testo.md": "24df1da31f19afae3f434032b447e804a8bcbdeeb1b270c6d04f28bfba5583fb", "notes/North Start.md": "662704939ce34782d6578cd8d91d5d7d738de19ce5eb34196f71733744bc1286", "README.md": "10ebf3cf75edbc6a6ccaf5c000185cde1e70bdc86c13d5b150d06546bad9c4dc", - "01. Projects/Escape Latam/Comparación de Paises.md": "6fb41dde50e73d696948be100340f951fc490f40cbcdda45584719fd7ba57194", "notes/Devlog.md": "8796c41169b072acea9ef97211e294ba7b464ccffabc1259c7763440fea7a63e", "01. Projects/Obtener pasaporte/Obtener pasaporte.md": "f3c1769ca0f40f87c41954c48b4cc791cf77dc22422e15a7005a880d9b030de9", - "01. Projects/Escape Latam/Escapar de Latam.md": "4ac856a52471f5eb6923790a96bbbf9daa867137cf9b8add09f498ba87e4469e", - "01. Projects/Escape Latam/New Zeldand.md": "c46e7d6cb08da2a7d5500640abc560f5db37dd056561420bce56df1c6eb485c7", - "01. Projects/Escape Latam/Canada.md": "974bdb92354ff2d46e67f524390bce477c8b0f753012f4f86eb0d4291b10a6ce", - "02. Areas/Dotfiles/dotfiles tasks.md": "bc454043d61c51de530e28dafe5b296077159e19b8c492f6d7de0d455b28bf32", - "01. Projects/Renuncia/Renuncia.md": "17d174d61ae84b4f1393490e5ea89832cc28b1aa7a53ec78016ea30a1fccdcd2", + "02. Areas/Dotfiles/dotfiles tasks.md": "9b662ba9122aaff0817522108a3a2dce6ee203b7f2c58abc8f4934e3899d878a", + "01. Projects/Renuncia/Renuncia.md": "088263e8c8b8719835e203690683861cd889b1c2a1bf17bdfa09243b8eadbe53", "01. Projects/Página Personal/board.md": "5ccecc6fd345d2e5361e6a55837716753426acbb020e4adcce89fc71c7d0b812", "02. Areas/Food/recipes.md": "320958ea965e90d56fd07f79928b046ce07755df3c05fe965a115c305aac3b07", "notes/asd.md": "e791e564d80d7b1354ef6dc05dab000a6ac265518f348d18db855d51264a8671", - "notes/Git.md": "33954c7b2255a032d400a87bcec9801fe8251583c092a383bd57f8571e9c7a90", "01. Projects/Electronic Mantainance/List of electronics.md": "cadf1bbd65c88be9d11f8992a4315c24e4a6d14b53b8f197159975217c2e347c", - "01. Projects/Fuuka/Outline.md": "6f86cc6dc7ccaa67aca79992e152584ccfe4d73ff0c259e67625c67ded5a47fa", - "01. Projects/Juuno/Outline.md": "6bb923894b595091a1d536e77b51b415ef7e69c0d95d59192c134ab23703b42d", + "01. Projects/Fuuka/Outline.md": "4a78de980ff0aa4f449ae017423b2a86be6a52f8e9f7594034bdf8fd9974de6d", + "01. Projects/Juuno/Outline.md": "c31e2610673db2be6e3064478a37e0dd44cd5cb107bc3c6b70f109467110a51f", "03. Resources/Notetaking/12. Questions.md": "a44916b14a0dd6f11280563bf77918df603b27bc1b43be7d4d41a9e71570cb3e", "03. Resources/Notetaking/CODE Method.md": "76e12aafc17b46efb83b49d0f4f9abe0aaa132770db931766a8cccebfa6a88ec", "03. Resources/Notetaking/North Start.md": "97cc810bb0609df94559cad725c88caec10b4bed33e220451ee6a4a05abb71de", @@ -44,6 +39,17 @@ "03. Resources/Notetaking/PARA method.md": "6b97f39b4fb42c6f9cdf52abb0221f9d802e163019fbc53d1a618d02e6ab2aaf", "03. Resources/Notetaking/Progresive Summarization.md": "9236f0faf755cc57e1d6e548f0727f6a2909cc847f8afbef3dc14fa43efa7a44", "01. Projects/Playa/comida.md": "0c27a53d357c1ffab1d4e6bf98545923dc211004041a3233528164ca47b0ef25", - "01. Projects/Playa/Comprar.md": "28114ba2502978f1a5a748766ed312dead7472155961ece2cf4b82aee13de322" + "01. Projects/Playa/Comprar.md": "28114ba2502978f1a5a748766ed312dead7472155961ece2cf4b82aee13de322", + "03. Resources/Notetaking/Habits.md": "2b6688471702b678ce2a8872ef86049592be866948871d8d3fbca5186f663d93", + "03. Resources/Development/Git.md": "f019123de154b2b1ea6bb2e60b7f0fe25094c9084c257c04c5e10f1fae0a7126", + "03. Resources/Development/Fix messy commits.md": "b1cd788af785ff651eed230eb313b09e984356de8bc2f1ab16b6858e2e5c6acf", + "03. Resources/Development/Revert old changes in a codebase.md": "6f2cd7c745d01436eac6ec8360de8085a7f1232f9fd3c21346e1a9ad15800dd2", + "03. Resources/Development/Search for a bug.md": "627a609a636453bd9de584ad559ea83338076fe656c08c90604f6551f79cab20", + "03. Resources/Development/Feature shipment checklist.md": "e6667e273f6553b4418039564f02dc51d5e83c5455d202cae4daf333914911be", + "03. Resources/Development/Iframes.md": "858ffe616925f94e6bfca207282649b111f134e30c67a76ddd0479c4f6193761", + "02. Areas/Escape Latam/Canada.md": "974bdb92354ff2d46e67f524390bce477c8b0f753012f4f86eb0d4291b10a6ce", + "02. Areas/Escape Latam/Comparación de Paises.md": "6fb41dde50e73d696948be100340f951fc490f40cbcdda45584719fd7ba57194", + "02. Areas/Escape Latam/Escapar de Latam.md": "4ac856a52471f5eb6923790a96bbbf9daa867137cf9b8add09f498ba87e4469e", + "02. Areas/Escape Latam/New Zeldand.md": "c46e7d6cb08da2a7d5500640abc560f5db37dd056561420bce56df1c6eb485c7" } } \ No newline at end of file diff --git a/01. Projects/Fuuka/Outline.md b/01. Projects/Fuuka/Outline.md index d3c53c8..e7a84c1 100644 --- a/01. Projects/Fuuka/Outline.md +++ b/01. Projects/Fuuka/Outline.md @@ -1,9 +1,11 @@ --- created: 2024-02-10 09:43 -updated: 2024-02-18 15:29 +updated: 2024-02-20 11:23 --- ## Maybe - Sería interesante tener un chat en el landing junto al "song request" - En el setup entre juno y fuuka en un docker-compose.yml, tendrá menos latencia montar un socket que por TCP? -- Implementar un "path mapping" similar a "arr's suit" \ No newline at end of file +- Implementar un "path mapping" similar a "arr's suit" +- Add meilisearch DB on top to add a "search bar" for music +- Add the option to allow or deny the song request while a playlist is playing \ No newline at end of file diff --git a/01. Projects/Juuno/Outline.md b/01. Projects/Juuno/Outline.md index 972a188..7fb1e64 100644 --- a/01. Projects/Juuno/Outline.md +++ b/01. Projects/Juuno/Outline.md @@ -1,8 +1,9 @@ --- created: 2024-02-10 09:45 -updated: 2024-02-18 15:29 +updated: 2024-02-20 11:48 --- - Juno sólo necesita que los archivos de música existan cuándo se le solicite ejecutarlo. - Randomize queue, diferente de shuffle mode - randomize, re-order the current queue in a random way - - shuffle, pick the next song at random from the current queue \ No newline at end of file + - shuffle, pick the next song at random from the current queue +- I can use [fd](https://github.com/sharkdp/fd) as reference for the filesystem exploration code \ No newline at end of file diff --git a/01. Projects/Renuncia/Renuncia.md b/01. Projects/Renuncia/Renuncia.md index 19b8370..e54a25b 100644 --- a/01. Projects/Renuncia/Renuncia.md +++ b/01. Projects/Renuncia/Renuncia.md @@ -1,5 +1,5 @@ --- created: 2024-02-06 14:27 -updated: 2024-02-18 15:29 +updated: 2024-02-20 11:50 --- - Con el finiquito puedo puedo ir a la AFC y obtener el seguro de cesantía en cuotas, que da más lucas. \ No newline at end of file diff --git a/02. Areas/Dotfiles/dotfiles tasks.md b/02. Areas/Dotfiles/dotfiles tasks.md index 4e88f12..c4482a6 100644 --- a/02. Areas/Dotfiles/dotfiles tasks.md +++ b/02. Areas/Dotfiles/dotfiles tasks.md @@ -1,6 +1,6 @@ --- created: 2024-02-06T14:24:00-03:00 -updated: 2024-02-18 15:29 +updated: 2024-02-20 11:52 type: Checklist --- @@ -10,3 +10,16 @@ type: Checklist - [ ] Añadir undo-tree to nvim - [ ] Terminar de configurar LF - [ ] Add mpv compact osd +- [ ] revisar default merge strategy for git +- [ ] Cambiar tipo de ventana para neogit +- [ ] Revisar [plugin](https://github.com/vimpostor/vim-tpipeline) to unify nvim and tmux status line +- [ ] Revisar ansible para inicializar dots +- [ ] Test out Ollama to see if resource usage is too high + +## Obsidian + +- [ ] Revisar plugins + - [ ] Media DB plugin + - [ ] Obsidian Tasks + - [ ] Obsidian Index Folder + \ No newline at end of file diff --git a/01. Projects/Escape Latam/Canada.md b/02. Areas/Escape Latam/Canada.md similarity index 100% rename from 01. Projects/Escape Latam/Canada.md rename to 02. Areas/Escape Latam/Canada.md diff --git a/01. Projects/Escape Latam/Comparación de Paises.md b/02. Areas/Escape Latam/Comparación de Paises.md similarity index 100% rename from 01. Projects/Escape Latam/Comparación de Paises.md rename to 02. Areas/Escape Latam/Comparación de Paises.md diff --git a/01. Projects/Escape Latam/Escapar de Latam.md b/02. Areas/Escape Latam/Escapar de Latam.md similarity index 100% rename from 01. Projects/Escape Latam/Escapar de Latam.md rename to 02. Areas/Escape Latam/Escapar de Latam.md diff --git a/01. Projects/Escape Latam/New Zeldand.md b/02. Areas/Escape Latam/New Zeldand.md similarity index 100% rename from 01. Projects/Escape Latam/New Zeldand.md rename to 02. Areas/Escape Latam/New Zeldand.md diff --git a/03. Resources/Development/Feature shipment checklist.md b/03. Resources/Development/Feature shipment checklist.md new file mode 100644 index 0000000..e3f7156 --- /dev/null +++ b/03. Resources/Development/Feature shipment checklist.md @@ -0,0 +1,9 @@ +--- +created: 2024-02-20 11:39 +updated: 2024-02-20 11:42 +--- +When a feature or module is shipt, I need to asure the following things before submiting: + +- Clean & readable code +- Linter without errors +- Design is as close as posible to the proposal \ No newline at end of file diff --git a/03. Resources/Development/Fix messy commits.md b/03. Resources/Development/Fix messy commits.md new file mode 100644 index 0000000..0b0733c --- /dev/null +++ b/03. Resources/Development/Fix messy commits.md @@ -0,0 +1,25 @@ +--- +created: 2024-02-20 11:27 +updated: 2024-02-20 11:31 +tags: + - dev-tools +--- +# Fix messy commits + +Ya que estas opciones sobre escriben el historial de git, solo deben aplicarse en local y no commits publicados a un remote. + +Como alternativa se puede intentar actualizar el historial remoto siempre y cuando el historial sea igual al local (osea, nosotros fuimos los últimos en actualizarlo y nadie ha hecho nada más). Para esto utilizamos `git push --force-with-lease`. + +## Last commit + +Si solo necesitamos agregar un cambio pequeño al ultimo commit (typo o correr el formatter), podemos aplicarlo con `git commit --ammend`, se puede sobre escribir el mensaje con `-m`. + +## Mutiple commits + +Se pueden arreglar el historial de commits con un `git rebase -i [since commit or branch]` y utilizar las estrategias de pick, squash, reword y drop. + +En caso de que sepamos que haremos un commit que luego no necesitaremos, podemos hacer: +- `git commit --fixup [commit hash]` -> descarta el commit message de este commit y mantiene el del commit de referencia +- `git commit --squash [commit hash]` -> git juntará los mensajes de todos los commits a hacer squash y el commit de referencia. + +Finalmente podemos hacer `git rebase -i --autosquash` y git eligirá las opciones necesarias a tomar en vez de tener que hacerlo de manera manual. diff --git a/03. Resources/Development/Git.md b/03. Resources/Development/Git.md new file mode 100644 index 0000000..1b851c6 --- /dev/null +++ b/03. Resources/Development/Git.md @@ -0,0 +1,15 @@ +--- +created: 2024-02-13 22:36 +updated: 2024-02-20 11:38 +tags: + - dev-tools +--- +## Merge strategies + + + + + + + + \ No newline at end of file diff --git a/03. Resources/Development/Iframes.md b/03. Resources/Development/Iframes.md new file mode 100644 index 0000000..cd4589d --- /dev/null +++ b/03. Resources/Development/Iframes.md @@ -0,0 +1,24 @@ +--- +created: 2024-02-20 11:43 +updated: 2024-02-20 11:45 +--- + +## How to make an Iframe 100% it's parent width while maintaining the aspect ratio + +In this example, we need to wrap the iframe in a container class and provide the following styles: + +```css +.container { + position: relative; + width: 100%; + height: 0; + padding-bottom: 56.25%; +} +iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +``` diff --git a/03. Resources/Development/Revert old changes in a codebase.md b/03. Resources/Development/Revert old changes in a codebase.md new file mode 100644 index 0000000..6093984 --- /dev/null +++ b/03. Resources/Development/Revert old changes in a codebase.md @@ -0,0 +1,15 @@ +--- +created: 2024-02-20 11:34 +updated: 2024-02-20 11:34 +tags: + - dev-tools +--- +## Revertir cambios + +Si necesitamos _"deshacer"_ los cambios introducidos en uno o multiples commits, podemos utilizar `git revert --no-edit older_commit_hashˆ..newer_commit_hash`, donde: + +- git realizará un nuevo commit con los cambios contrarios por cada commit en el rango +- utilizar `ˆ` en el `old_commit_hash` incluirá ese commit en la reversión de cambios, si no se agrega se empezará a revertir de un commit más adelante. +- `--no-edit` es utilizado para que git no nos pregunte por el message de cada nuevo commit +- primero debe ser el commit más antiguo, porque git creará nuevos commits en orden provisto y de hacerlo al revés aparecerán conflictos +- si solo se quiere revertir un commit, se puede especificar solo ese hash diff --git a/03. Resources/Development/Search for a bug.md b/03. Resources/Development/Search for a bug.md new file mode 100644 index 0000000..17eeea6 --- /dev/null +++ b/03. Resources/Development/Search for a bug.md @@ -0,0 +1,9 @@ +--- +created: 2024-02-20 11:35 +updated: 2024-02-20 11:37 +--- +# Buscar cuando un bug se introdujo + +## Utilizar `git bisect` + +`git bisect` hará un _"binary search"_ entre 2 commits, dejandonos señalar si este commit es _"bueno"_ (no tiene el bug) o _"malo"_ (tiene el bug), permitiendo encontrar el commit que introdujo el bug y facilitar encontrar la causa de este. \ No newline at end of file diff --git a/03. Resources/Notetaking/Habits.md b/03. Resources/Notetaking/Habits.md new file mode 100644 index 0000000..e62d7e2 --- /dev/null +++ b/03. Resources/Notetaking/Habits.md @@ -0,0 +1,22 @@ +--- +created: 2024-02-20 11:14 +updated: 2024-02-20 11:18 +--- +# Habits to apply while notetaking process + +## Project checklist + +### Kickoff + +### Completion + +## Periodic reviews + +This should be forgiving, doesn't bad happens if I miss a review day +### Weekly + +### Monthly + +## Noticing other habits + +Do this inh small chunks while using the second brain \ No newline at end of file diff --git a/Read Later/2024-02-12 - Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React.md b/Read Later/2024-02-12 - Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React.md new file mode 100644 index 0000000..a979606 --- /dev/null +++ b/Read Later/2024-02-12 - Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React.md @@ -0,0 +1,412 @@ +--- +id: d529f41a-ca28-11ee-97f3-f78c291f6623 +title: | + Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React +status: ARCHIVED +tags: + - read-later + - RSS +date_added: 2024-02-12 20:23:30 +url_omnivore: | + https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510 +url_original: | + https://www.freecodecamp.org/news/deboucing-in-react-autocomplete-example/ +--- + +# Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React + +## Highlights + +Debouncing accepts a function and transforms it in to an updated (debounced) function so that the code inside the original function is executed after a certain period of time. + +[source](https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510#2c8f31bd-f011-49bd-99bc-36192f7fd823) + +--- + +function debounce(func, delay) {let timeout=null return (...args) => {if(timeout) clearTimeout(timeout) timeout=setTimeout(() \=> { func(...args) timeout=null }, delay) } } + +[source](https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510#5a57c802-520a-409a-a51c-e554a6ec8bd5) + +--- + +const useDebounce = (func, delay) => { let timeout\=null return (...args) => {if(timeout) clearTimeout(timeout)timeout\=setTimeout(() => { func(...args) }, delay) } }export default useDebounce + +[source](https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510#226d8c7b-6900-4b2f-a705-5f5b6e10afc5) + +--- + +## Original + + + +Hi readers, I hope you are doing great! I am back with another tutorial on web development. If you are someone who enjoys developing web apps with JavaScript and React, then this post is for you. + +When you roll out a new app into production, you want to make sure that it's user friendly. A website's performance is a key part of the user experience. Every user wants the website and its contents to load quickly. Each and every second is valuable and could result into a user never visiting your website again. + +In this guide, we are going to understand a very important technique in JavaScript known as debouncing. Then, I will show you how to implement the autocomplete functionality in React with debouncing. + +Now, in order to get the most out of this tutorial, I am assuming you have a basic knowledge of JavaScript. If you need to get started or review, here are a couple resources for you: + +* Learn JavaScript basics – [handbook for beginners](https://www.freecodecamp.org/news/learn-javascript-for-beginners/) +* The freeCodeCamp [JavaScript Algorithms and Data Structures certification](https://www.freecodecamp.org/news/learn-javascript-with-new-data-structures-and-algorithms-certification-projects/) + +## **Table of Contents:** + +* [What is Debouncing?](#what-is-debouncing) +* [How to Implement Debouncing in JavaScript](#how-to-implement-debouncing-in-javascript) +* [Use Case of Debouncing](#use-case-of-debouncing) +* [Conclusion](#conclusion) + +## What is Debouncing? + +Debouncing is a strategy used to improve the performance of a feature by controlling the time at which a function should be executed. + +==Debouncing accepts a function and transforms it in to an updated (debounced) function so that the code inside the original function is executed after a certain period of time.== + +If the debounced function is called again within that period, the previous timer is reset and a new timer is started for this function call. The process repeats for each function call. + +An example will help you understand better. Let's take a function `fun()`. We want this function to execute after 500ms. + +```crystal +function fun() { + console.log('This is a function') +} +``` + +After debouncing, a new function `debouncedFun()` is returned. Now, whenever you call `debouncedFun()`, it will be called after 500ms. + +If you call it again within the next 500ms after first calling it, the previous timer is reset and a new timer is started for the second function call. The process repeats if you keep calling the function within 500ms. + +## How to Implement Debouncing in JavaScript + +Let's understand how to implement debouncing in JavaScript. First, we'll go over our requirements. What behavior do we want from the debounced function? + +* Delay the function execution by a certain time, `delay`. +* Reset the timer if the function is called again. + +To debounce a function, we'll have a separate function that accepts the function reference and the delay as parameters, and returns a debounced function. + +```ada +function debounce(func, delay) { + return () => {} // return debounced function +} +``` + +This function will only be called once to return a debounced function and that, in turn, will be used in the subsequent code. + +To delay a function by some milliseconds, we can simply use the `setTimeout` function in JavaScript. + +```arcade +function debounce(func, delay) { + return () => { + setTimeout(() => { + func() + }, delay) + } +} +``` + +This delays the function call by `delay` milliseconds. But this is incomplete as it only satisfies the first requirement. How do we achieve the second behaviour? + +Let's create a variable `timeout` and assign it to the return value of `setTimeout` method. The `setTimeout` method returns a unique identifier to the timeout, which is held by `timeout` variable. + +```javascript +function debounce(func, delay) { + let timeout=null + return () => { + timeout=setTimeout(() => { + func() + }, delay) + } +} +``` + +Each time you invoke `setTimeout`, the ID is different. We will use this `timeout` variable to reset the timer. + +But how do we get access to `timeout` from outside the `debounce()` method? As mentioned before, `debounce()` is only used once to return a debounced function. This, in turn, performs the debouncing logic. + +Then, how does the debounced function have access to `timeout` even if it is used outside the `debounce()` function? Well, it uses a concept called closure. + +### What's a closure in JavaScript? + +In JavaScript, an inner function always has access to the local variables of the outer function. In our case, the inner function has access to `timeout` that has function level scope in the `debounce()` method. + +But when the outer function returns this inner function, the inner function still holds a reference to the local variables of the outer function long after the outer function has finished execution. This is the concept of a closure. + +Let's understand closures with an example. + +```javascript +function outerFunction() { + const x = 5; + + return () => { + console.log(x); + } +} + +const inner = outerFunction(); + +inner(); // prints 5 + +// console.log(x) Throws reference error +``` + +Here, if we call `inner()`, the code runs without any errors and prints 5\. But, if we try to access `x` directly, JavaScript throws a reference error. + + + +JavaScript Reference Error + +Here, `inner()` closes over `x` and only this function can use the variable and no one other one can. We cannot access the variable explicitly. + +You can check out [this beginner-friendly tutorial](https://www.freecodecamp.org/news/closures-in-javascript/) to learn more about closures. + +### Back to Debouncing + +Let's get back to where we left off: + +```javascript +function debounce(func, delay) { + let timeout=null + return () => { + timeout=setTimeout(() => { + func() + }, delay) + } +} +``` + +Here, JavaScript uses a closure to hold access to `timeout` every time we use the debounced function. + +Let's use this to our advantage. Since `debouncedFun()` has access to the same `timeout` variable in every function call, we can add a condition to check whether a previous timeout exists. We can simply do this with a null check, `if(timeout !== null)` or `if(timeout)`. + +Then, we use the `clearTimeout()` method to cancel the previous timeout, thus resetting the timer. + +Add the following statement before starting a new timeout: + +```lisp +if(timeout) + clearTimeout(timeout) + +``` + +Once the timeout is reset, a new timeout is started for the current function call, whose ID is then assigned to `timeout`. The process is repeated for the subsequent function calls who have access to the same `timeout` due to closures. + +```javascript +function debounce(func, delay) { + let timeout=null + return () => { + if(timeout) clearTimeout(timeout) + + timeout=setTimeout(() => { + func() + }, delay) + } +} +``` + +With this, we have satisfied our second requirement – that is, resetting the timer and starting a new one. It's time to use this debounced function. + +Let's pass `fun()` to the `debounce()` method with a delay of 500ms. + +```kotlin +const debouncedFun = debounce(fun, 500) + +``` + +`debouncedFun()` is basically `fun()` with debouncing behaviour. Let's call this function at different time intervals to test our functionality. + +```stylus +debouncedFun() + +setTimeout(debouncedFun, 300) + +setTimeout(debouncedFun, 900) +``` + +The first function call is made instantly. The other two are made after 300ms and 900ms respectively. Can you guess the output? + +The code prints `This is a function` two times. Let's understand why. Here, after the first call is made, `fun()` is scheduled to execute after 500ms. But the second one is made in 300ms which resets the timer and starts a new one. + +500ms have passed and the `fun()` method executes. Then, at 900ms, another function call is made. This again executes `fun()` after 500ms. + +There is still a small improvement we should make. Our logic does not consider function arguments. Let's replace `fun()` with `fun(a, b)`. + +```javascript +function fun(a, b) { + console.log(`This is a function with arguments ${a} and ${b}`) +} +``` + +To incorporate arguments while debouncing, return a debounced function that accepts arguments. + +```javascript +function debounce(func, delay) { + let timeout=null + return (...args) => { + if(timeout) clearTimeout(timeout) + + timeout=setTimeout(() => { + func(...args) + timeout=null + }, delay) + } +} +``` + +By using the spread operator, any arguments passed to the debounced function will be stored as an array in the `args` variable. Then, spread out the same `args` array to call the actual function with the arguments passed. + +```kotlin +const debouncedFun=debounce(fun, 500) +debouncedFun(2,3) +``` + +The above code prints `This is a function with arguments 2 and 3` after 500ms. + +## Use Case of Debouncing + +Let's see how debouncing is used in practical applications. The most common use case of debouncing is the autocomplete functionality. You must have seen many websites where you type into an input field and it shows a list of results as you type them. + +Here's an example from Google Search: + + + +Google Search Autocomplete after typing in "Top 10" + +Google search shows the most recent and commonly searched terms. The information is mostly fetched from the browser cache. But, several websites make API calls to backend server to fetch the data from a database. + +This can easily be implemented by adding an `onchange` event to the `input` element and implementing the fetch logic in the event handler. But there's a slight issue with this. + +Consider the following example: + + + +API Request made for each input value + +When I type the word _absolute_, an API request is made every time the value of the input field changes. We are making 8 API requests in very few milliseconds which puts a lot of load on the backend server and could cause performance issues. + +Ideally, we want to show the auto-complete results some time after the user has finished typing. Here, the user has typed _absolute_ in one go, so instead of showing results every time the input changes, we could show them once the user has finished typing – that is, we could add some delay between the input change and the results being displayed. + +So, we only make the API calls when the user finishes typing their word and not on every input change. This reduces the number of API calls and improves performance. We can achieve this behavior with debouncing. + +Let's understand how to implement the autocomplete functionality in React. + +### Auto-complete example + +Use `create-react-app` (or a modern build tool like Vite) to create the project. Remove the existing boilerplate code. There is no need to install any additional dependencies. Run `npm start` command to start the project. You can find the complete code on [GitHub](https://github.com/KunalN25/react-debouncing). + +I have set up a Node server to fetch data for the app. You can find it in the Git repo. Run the `node server` command to start it. I am not going to show the Node.js code as it's out of the scope of this tutorial. + +Let's get started with the implementation. We will write a simple autocomplete functionality. The app should show a list of cities that contain an input string typed by the user. + +#### App Component + +We'll first need an `input` element to accept user input and a _results container_ for the search results. Attach an event handler to the `input` element which is an `async` function since it will include the fetching logic. + +```javascript +function App() { + const [data, setData] = useState(null) + + const loadData = async (event) => { + + } + return ( +
{item.city}
+