Как вы выполняете debounce в React.js?
Я хочу разоблачить handleOnChange.
Я пытался с, debounce(this.handleOnChange, 200)
но это не работает.
function debounce(fn, delay) {
var timer = null;
return function() {
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
var SearchBox = React.createClass({
render: function() {
return <input type="search" name="p" onChange={this.handleOnChange} />;
},
handleOnChange: function(event) {
// make ajax call
}
});
javascript
reactjs
Четан Анкола
источник
источник
debounce
. здесь, когдаonChange={debounce(this.handleOnChange, 200)}/>
он будет вызыватьdebounce function
каждый раз. но на самом деле нам нужно вызвать функцию, возвращаемую функцией debounce.Ответы:
2019: попробовать крючки + обещание разоблачения
Это самая актуальная версия того, как бы я решил эту проблему. Я хотел бы использовать:
Это некоторая начальная схема, но вы сами составляете примитивные блоки, и вы можете создать свой собственный пользовательский хук, так что вам нужно будет сделать это только один раз.
И тогда вы можете использовать свой крючок:
Вы найдете этот пример запущенным здесь, и вы должны прочитать документацию о реакции-асинхронности для получения более подробной информации.
2018: попробуйте обещать разоблачение
Мы часто хотим отменить вызовы API, чтобы избежать затопления серверной части бесполезными запросами.
В 2018 году работа с обратными вызовами (Lodash / Underscore) кажется мне плохой и подверженной ошибкам. Проблемы с параллельным доступом и параллелизмом легко возникают из-за разрешения вызовов API в произвольном порядке.
Я создал небольшую библиотеку с React для решения ваших проблем: awesome-debounce-обещание .
Это не должно быть сложнее, чем это:
Деблокированная функция гарантирует, что:
this.setState({ result });
вызов произойдет за вызов APIВ конце концов, вы можете добавить еще один трюк, если ваш компонент размонтируется:
Обратите внимание, что Observables (RxJS) также могут отлично подходить для разбора входных данных, но это более мощная абстракция, которую может быть сложнее правильно изучить / использовать.
<2017: все еще хотите использовать обратный вызов?
Важной частью здесь является создание единой дебазированной (или регулируемой) функции для каждого экземпляра компонента . Вы не хотите каждый раз воссоздавать функцию debounce (или throttle), и вы не хотите, чтобы несколько экземпляров использовали одну и ту же функцию debounce.
В этом ответе я не определяю функцию
_.debounce
устранения неполадок, так как она не очень актуальна, но этот ответ будет прекрасно работать с подчеркиванием или переводом строки, а также с любой предоставленной пользователем функцией устранения неполадок.ХОРОШАЯ ИДЕЯ:
Поскольку отклоняемые функции сохраняют состояние, мы должны создать одну отклоненную функцию на экземпляр компонента .
ES6 (свойство класса) : рекомендуется
ES6 (конструктор класса)
ES5
См. JsFiddle : 3 экземпляра создают 1 запись в журнале за экземпляр (что составляет 3 глобально).
Не хорошая идея:
Это не сработает, потому что при создании объекта описания класса
this
это не сам объект, созданный.this.method
не возвращает то, что вы ожидаете, потому чтоthis
контекст не является самим объектом (который на самом деле еще не существует, кстати, поскольку он только создается).Не хорошая идея:
На этот раз вы эффективно создаете дебагованную функцию, которая вызывает вашу
this.method
. Проблема в том, что вы воссоздаете его при каждомdebouncedMethod
вызове, поэтому вновь созданная функция debounce ничего не знает о предыдущих вызовах! Вы должны повторно использовать одну и ту же отклоненную функцию с течением времени, иначе удаление не произойдет.Не хорошая идея:
Это немного сложно здесь.
Все подключенные экземпляры класса будут использовать одну и ту же функцию, от которой отказались, и чаще всего это не то, что вам нужно! См. JsFiddle : 3 экземпляра производят только 1 запись журнала во всем мире.
Для каждого экземпляра компонента необходимо создать неработающую функцию , а не отдельную деблокированную функцию на уровне класса, которая будет использоваться каждым экземпляром компонента.
Позаботьтесь о пуле событий React
Это связано с тем, что мы часто хотим отсеивать или ограничивать события DOM.
В React объекты событий (т. Е.), Которые
SyntheticEvent
вы получаете в обратных вызовах, объединяются (теперь это задокументировано ). Это означает, что после вызова обратного вызова события полученный SyntheticEvent будет помещен обратно в пул с пустыми атрибутами, чтобы уменьшить нагрузку на GC.Поэтому, если вы
SyntheticEvent
обращаетесь к свойствам асинхронно с исходным обратным вызовом (как это может быть в случае, если вы дросселируете / отклоняете), свойства, к которым вы обращаетесь, могут быть удалены. Если вы хотите, чтобы событие никогда не возвращалось в пул, вы можете использоватьpersist()
метод.Без сохранения (поведение по умолчанию: объединенное событие)
2-й (асинхронный) будет напечатан,
hasNativeEvent=false
потому что свойства события были очищены.С упорством
2-й (асинхронный) будет печатать,
hasNativeEvent=true
потому чтоpersist
позволяет избежать возврата события в пул.Вы можете проверить эти 2 поведения здесь: JsFiddle
Прочитайте ответ Джулена для примера использования
persist()
с функцией throttle / debounce.источник
handleOnChange = debounce((e) => { /* onChange handler code here */ }, timeout)
на верхнем уровне вашего класса. Вы по-прежнему эффективно устанавливаете элемент экземпляра, но это выглядит немного больше как обычное определение метода. Нет необходимости,constructor
если у вас его еще нет. Я полагаю, это в основном стиль предпочтений.componentWillUnmount
:this.method.cancel()
- в противном случае он может захотеть установить setState для несмонтированного компонента.Неконтролируемые компоненты
Вы можете использовать
event.persist()
метод .Пример следует с использованием подчеркивания
_.debounce()
:Редактировать: см. Это JSFiddle
Контролируемые компоненты
Обновление: в примере выше показан неконтролируемый компонент . Я все время использую контролируемые элементы, так что вот еще один пример выше, но без использования
event.persist()
«хитрости».JSFiddle доступен , а также. Пример без подчеркивания
Изменить: обновленные примеры и JSFiddles для реагирования 0,12
Изменить: обновленные примеры для решения проблемы, поднятой Себастьеном Лорбером
Редактировать: обновлено с помощью jsfiddle, который не использует подчеркивания и использует простой отладочный код javascript.
источник
<input value={this.props.someprop}...
его, он не будет отображаться должным образом, так как обновление по нажатию клавиши не вернет его обратно в компонент до окончания отладки. Можно неvalue=
указывать, если вы рады, что это неуправляемо, но если вы хотите предварительно заполнить значение и / или связать его где-то еще, тогда, очевидно, это не сработает.persist
особенно когда может быть много событий, напримерmousemove
. Я видел, как код стал полностью безразличным таким образом. Гораздо эффективнее извлечь необходимые данные из собственного события в вызове события, а затем вызвать функцию debounce / throttled только с данными, а не с самим событием. Не нужно так настаивать на этом событии2019: использовать хук реакции useCallback
Перепробовав много разных подходов, я обнаружил, что использование
useCallback
является самым простым и наиболее эффективным в решении проблемы множественных вызовов при использованииdebounce
вonChange
событии.Согласно документации Hooks API ,
Передача пустого массива в качестве зависимости гарантирует, что обратный вызов вызывается только один раз. Вот простая реализация:
Надеюсь это поможет!
источник
debounce()
считает лиonChange()
обратный вызов тем же методом обратного вызова?const testFunc2 = useCallback(debounce((text) => console.log('testFunc2() has ran:', text), 1000) , []);
внутри тела компонента функции или React выдает сообщение об ошибке использования крючка за ее пределами. Тогда вonChange
обработчик событий:<input type='text' name='name' className='th-input-container__input' onChange={evt => {testFunc2(evt.target.value);}}
.Я нашел этот пост Джастином Тулком очень полезным. После нескольких попыток, что, как можно было бы воспринимать как более официальный способ с реакцией / редукцией, показывает, что он терпит неудачу из-за искусственного объединения событий в React . Затем его решение использует некоторое внутреннее состояние для отслеживания значения, измененного / введенного во входных данных, с обратным вызовом, сразу после
setState
которого вызывается дросселированное / дебазованное избыточное действие, которое показывает некоторые результаты в реальном времени.источник
Если все, что вам нужно от объекта события, - это получить элемент ввода DOM, решение будет намного проще - просто используйте
ref
. Обратите внимание, что это требует подчеркивания :источник
Поработав некоторое время с текстовыми вводами и не найдя идеального решения самостоятельно, я нашел это на npm: реагировать-отсеивать-вводить .
Вот простой пример:
Компонент DebounceInput принимает все реквизиты, которые вы можете назначить обычному элементу ввода. Попробуйте это на codepen
Я надеюсь, что это поможет кому-то еще и сэкономит им время.
источник
С
debounce
вами нужно сохранить оригинальное синтетическое событиеevent.persist()
. Вот рабочий пример, проверенный сReact 16+
.С функциональным компонентом вы можете сделать это -
Ссылки - - https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709 - https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html
источник
Если вы используете redux, вы можете сделать это очень элегантно с промежуточным программным обеспечением. Вы можете определить
Debounce
промежуточное программное обеспечение как:Затем вы можете добавить debouncing для создателей действий, таких как:
На самом деле уже есть промежуточное ПО, которое вы можете отключить, чтобы сделать это за вас.
источник
applyMiddleware(...)
цепочке, если у нас их многоИспользование ES6 CLASS и React 15.xx & lodash.debounce Im используя РЕАКТ рефов здесь , поскольку потери Ивентов это связывают внутренне.
источник
Здесь уже много хорошей информации, но, чтобы быть кратким. Это работает для меня ...
источник
_debounce
обертку, это работает. Я люблю эту идею, хотя!Вы можете использовать метод отката Lodash https://lodash.com/docs/4.17.5#debounce . Это просто и эффективно.
Вы также можете отменить метод debounce, используя метод ниже.
Надеюсь, это поможет вам. Ура !!
источник
FYI
Вот еще одна реализация PoC:
Я надеюсь, что это помогает :)
источник
Есть
use-debounce
пакет, который вы можете использовать с перехватчиками ReactJS.Из пакета README:
Как видно из приведенного выше примера, он настроен на обновление переменной
value
только один раз в секунду (1000 миллисекунд).источник
Просто еще один вариант с недавними реакциями и лодашами.
источник
Хорошее и чистое решение, которое не требует каких-либо внешних зависимостей:
Разоблачение с помощью React Hooks
Он использует пользовательский плюс useEffect Реагировать крюки и
setTimeout
/clearTimeout
метод.источник
Ты пробовал?
источник
Вместо того, чтобы оборачивать handleOnChange в debounce (), почему бы не обернуть вызов ajax внутри функции обратного вызова внутри debounce, тем самым не уничтожив объект события. Так что-то вроде этого:
источник
Вот пример, который я придумал, который связывает другой класс с debouncer. Это прекрасно подходит для превращения в функцию декоратора / высшего порядка:
источник
В конце 2019 года есть еще одно решение для React и React Native :
реагирует-дребезг-компонентный
Это простой в использовании компонент, крошечный и поддерживаемый Wideley
Пример:
* Я создатель этого компонента
источник
Я искал решение той же проблемы и наткнулся на этот поток, а также на некоторые другие, но у них была та же проблема: если вы пытаетесь выполнить
handleOnChange
функцию и вам нужно значение из целевого объекта события, вы получитеcannot read property value of null
или несколько такая ошибка. В моем случае мне также нужно было сохранить контекстthis
внутри обсуждаемой функции, так как я выполняю гибкое действие. Вот мое решение, оно хорошо работает для моего варианта использования, поэтому я оставляю его здесь на случай, если кто-нибудь натолкнется на эту тему:источник
за
throttle
илиdebounce
лучший способ - создать создателя функции, чтобы вы могли использовать его где угодно, например:и в вашем
render
методе вы можете сделать:updateUserProfileField
метод создаст Отделимую функцию каждый раз , когда вы называете его.Примечание: не пытайтесь вернуть обработчик напрямую, например, это не будет работать:
причина, по которой это не будет работать, потому что это будет генерировать новую функцию газа каждый раз, когда вызывается событие, а не использовать ту же функцию газа, поэтому в принципе газ будет бесполезен;)
Кроме того, если вы используете,
debounce
илиthrottle
вам не нужно,setTimeout
илиclearTimeout
это то, почему мы используем их: Pисточник
Вот фрагмент кода, использующий подход @ Abra, обернутый в компонент функции (мы используем fabric для пользовательского интерфейса, просто замените его простой кнопкой)
источник
Мое решение основано на хуках (написано в Typescript).
У меня есть 2 основных крючка
useDebouncedValue
иuseDebouncedCallback
Первый -
useDebouncedValue
Допустим, у нас есть окно поиска, но мы хотим запросить у сервера результаты поиска после того, как пользователь перестал печатать в течение 0,5 с.
Реализация
второй
useDebouncedCallback
Он просто создает «дебагованную» функцию в области действия вашего компонента.
Допустим, у нас есть компонент с кнопкой, которая будет показывать предупреждение через 500 мс после того, как вы перестанете его нажимать.
Реализация (обратите внимание, я использую lodash / debounce в качестве помощника)
источник
Вот рабочий пример TypeScript для тех, кто использует TS и хочет отменить
async
функции.источник
немного поздно здесь, но это должно помочь. создать этот класс (он написан на машинописном тексте, но его легко конвертировать в javascript)
и использовать
источник
Вы можете использовать Tlence Tlence
источник
Решение Julen довольно сложно прочитать, здесь приведен более понятный и точный код реагирования для любого, кто наткнулся на него, основываясь на названии, а не на крошечных деталях вопроса.
tl; dr version : когда вы обновляете наблюдателей, вместо этого отправляйте метод вызова по расписанию, который, в свою очередь, будет фактически уведомлять наблюдателей (или выполнять ajax и т. д.)
Завершите jsfiddle с примером компонента jsfiddle
источник
Избегайте использования
event.persist()
- вы хотите позволить React перезапустить синтетическое событие. Я думаю, что самый простой способ использовать классы или ловушки - это разделить обратный вызов на две части:Классы
функции
Обратите внимание , что если ваша
handleMouseOver
функция использует состояние внутри компонента, вы должны использоватьuseMemo
вместоuseRef
и передавать их в качестве зависимостей иначе вы будете работать с устаревшими данными (не относится к классам, конечно).источник
Расширить useState hook
Использовать крюк
https://trippingoncode.com/react-debounce-hook/
источник
Встретил эту проблему сегодня. Решил это используя
setTimeout
иclearTimeout
.Я приведу пример, который вы могли бы адаптировать:
Вы также можете изменить его в компоненте своей функции:
И используйте это как:
источник