предисловие
И props, и state — это js-объекты, используемые компонентами для хранения данных.Первый — для предоставления интерфейса данных внешнему миру, а второй — состояние внутреннего компонента.Они определяют форму отображения UI-интерфейса, и если вы хотите какое-то взаимодействие между пользователем и интерфейсом
То есть веб-браузер уведомляет приложение о том, что произошло, например: клики мышью, движения, нажатия клавиш и т. д. Соответствующая обратная связь происходит на странице, которая является моментом некоторого конкретного взаимодействия между пользователем и документом или браузером. окно. В это время нужно использовать события
В работе нативный JS DOM, часто встроенный
- Прямая привязка событий в HTML
<p onclick="alert('关注微信itclanCoder公众号')"></p>
- прямое связывание
对象.事件类型 = 匿名函数,obj.onclick = function(){})`
Выполнение обработки мониторинга событий на объектах DOM, метод мониторинга делегирования событий
(对象.addEventListener('事件类型,不带on', 回调函数))
В React обработка событий и встраивание похожи, но немного отличаются Как вы гарантируете, что функции могут получить доступ к свойствам компонента?
Как передать параметры обратным вызовам обработчиков событий?
Как сделать, чтобы функции не вызывались слишком быстро или слишком много раз, какое решение?
Частые манипуляции с DOM приведут к зависанию и зависанию браузера, заставляя браузер перерисовывать и изменять порядок, что увеличивает нагрузку на браузер.
Частые обращения к фоновому интерфейсу, хороший интерфейс нарушается вами, в результате чего страница становится пустой и вылетает, и ее легко увидеть одноклассникам из бэкенда.
Для улучшения взаимодействия с пользователем и снижения накладных расходов на стороне сервера
Тогда это то, что вы хотите знать
Обработка событий в React, лучший опыт чтения
События в React
В React привязка события записывается непосредственно в элемент JSX, и ее не нужно отслеживать с помощью делегирования события addEventListener. На письме:
-
Добавляйте события в элементы JSX через
on*EventType
Этот встроенный способ добавляет,命名采用小驼峰式(camelCase)的形式,而不是纯小写
(В нативном HTML события привязаны к элементам DOM, а тип события указан в нижнем регистре), нет необходимости вызывать addEventListener для мониторинга событий и нет необходимости учитывать совместимость. React инкапсулировал некоторые атрибуты типа события (ps: onClick, onMouseMove, onChange, onFocus) и т. д. - При использовании синтаксиса JSX вам нужно передать функцию как обработчик события, а не строку, то есть значение реквизита должно быть данными типа функции, а метод функции события должен быть заключен в двойные фигурные скобки.
-
on*EventType的事件类型属性,只能用作在普通的原生html标签上
(например: div, input, a, p и т. д., например:<div onClick={ 事件处理函数 }></div>
),Нельзя использовать непосредственно в тегах пользовательских компонентов.,То есть: , это не работает - Поведение по умолчанию нельзя предотвратить, возвращая false, использование preventDefault должно отображаться, как показано ниже.
function handleClick(event){
event.preventDefault();
}
объект события
События — это веб-браузеры, уведомляющие приложение о том, что произошло, например: щелчки мышью, движения, нажатия клавиш и т. д.
Это не объект javascript, но функция обработчика событий, запускаемая событием, получает передаваемый параметр объекта события (событие) и записывает некоторую подробную информацию о событии.
<a href="#" onClick = { this.handleLink} >链接</a>
handleLink(event){
event.preventDefault();
console.log(event);
}
событие будет записывать информацию об объекте события, как показано на следующем рисунке.
Когда функция обработчика событий привязана к элементу DOM, функция автоматически передает объект события, который записывает свойства и методы текущего события с общим объектом браузера.В React объект события не предоставляется браузером. Вы можете понимать его как объект события React. React инкапсулирует объект события собственного браузера и предоставляет общедоступный интерфейс API без учета каждого браузера.
То же, что и встроенная браузерная обработка всплывающих окон событий ( event.stopPropatation ) и предотвращение поведения по умолчанию ( event.preventDefault )
это сравнение производительности привязки
В предыдущем разделе была изучена привязка этого, и вынесено в свое время для объяснения его важности
Обычно при привязке обработчика прослушивателя событий к элементу JSX для этой привязки привязывайте обработчик событий к экземпляру текущего компонента: чтобы получить реквизиты от родительского компонента
Есть несколько способов гарантировать, что функции могут получить доступ к свойствам компонента.
- привязать в конструктореПривяжите эту среду в конструкторе и инициализируйте обработчик прослушивателя событий.
class Button extends Component{
constructor(props){
super(props);
// 在构造器函数中进行this坏境的绑定
this.handleBtnClick = this.handleBtnClick.bind(this);
}
render(){
return (
<div>
<button onClick={ this.handleBtnClick }>按钮</button>
</div>
);
}
handleBtnClick(){
alert(this);
}
}
При выполнении привязки мониторинга событий на JSX, для этого в функции обратного вызова JSX, потому что метод класса в Es6 не будет связывать это по умолчанию, если вы не выполняете плохую привязку среды этого, забудьте привязать функцию обработки событий и передать его методу события (onClick выше), тогда значение this не определено
Чтобы решить эту проблему: нужно связать эту среду в функции конструктора, как указано выше, что официально рекомендуется React и имеет лучшую производительность.
Второй способ — привязать это напрямую к JSX, через привязку в Reander.
<button onClick={ this.handleBtnClick.bind(this) }>按钮</button>
Используя эту прямую привязку привязки, каждый раз, когда компонент визуализируется, будет создаваться новая функция.Вообще говоря, нет никаких проблем с этим способом написания, но если функция обратного вызова передается как значение свойства дочерним компонентам, эти Компоненты будут выполнять дополнительный повторный рендеринг, что повлияет на производительность, что является той же проблемой, что и использование стрелочных функций.
Решение:
- Выполните привязку в функции конструктора, как показано выше:
- Используйте синтаксис полей класса
class Button extends Component{
// 类字段的形式进行绑定,函数表达式
handleClick = () => {
alert("学习React基础内容");
}
render(){
return (
<div>
<button onClick={ this.handleBtnClick }>按钮</button>
</div>
);
}
}
Вместо синтаксиса поля класса в обратных вызовах можно использовать стрелочные функции, которые эквивалентны
class Button extends Component{
handleClick()
alert("学习React基础内容");
}
render(){
return (
<div>
<button onClick={ () => { this.handleBtnClick } }>按钮</button>
</div>
);
}
}
Этот метод имеет ту же проблему с производительностью, что и использование bind для привязки этой среды непосредственно в функции Render.Когда обработчик события передается дочернему компоненту в качестве реквизита, это обязательно вызовет рендеринг функции Render.
Поэтому по соображениям производительности поместите привязку this в функцию конструктора или используйте синтаксис полей класса, чтобы решить это узкое место производительности.
Передать параметры обработчикам событий
В списке операций цикла, иногда для реализации тех или иных операций нам необходимо передать в обработчик события некоторые дополнительные параметры, такие как: индекс, ID какой строки удалить Существует два способа передачи параметров обработчикам событий.
<button onClick = { this.handleBtnDelete.bind(this,id)}>删除</butto/n>
或者
<button onClick = { (e) => this.handleDelete(id, e) }>删除</button>
Ниже приведен пример удаления списка, эффект следующий, показан код
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
class List extends Component {
constructor(props){
super(props);
const { list } = this.props;
this.state = {
list: list
}
}
render(){
const { list } = this.state;
return (
<Fragment>
<ul>
{
// list.map((item, index) => <li onClick={ this.handleDelete.bind(this, index)} key={index}>{ item }</li>)
list.map((item, index) => <li onClick={ (e) => this.handleDelete(index, e)} key={index}>{ item }</li>)
}
</ul>
</Fragment>
);
}
handleDelete(index, e){
console.log(e)
// 拷贝state的一个副本,不要直接的去更改state,在React中,不允许对state做任何改变
const list = [...this.state.list];
list.splice(index,1);
this.setState(() => ({
list: list
}))
}
}
const listData = ["itclanCoder", "川川", "chrome", "Firefox", "IE"]
const container = document.getElementById('root');
ReactDOM.render(<List list={ listData } />, container);
В приведенном выше коде привязка (Function.proptype.bind) в функции рендеринга и обертывание обработчика событий стрелочной функцией и передача параметров в функцию обработчика событий эквивалентны
<button onClick = { this.handleBtnClick(this, id)}></button>
// 等价于
<button onClick = { () => this.handleBtnClick(id) }></button>
Если используются стрелочные функции, объект события React будет передан в качестве второго параметра, и его необходимо передать явно
И через метод привязки объект события и другие параметры будут неявно переданы в
Связывание напрямую через метод bind в функции рендеринга будет создавать новую функцию каждый раз при рендеринге компонента, что повлияет на производительность: лучше всего связать это окружение в функции конструктора, потому что конструктор Функция будет выполняться только один раз
constructor(props){
super(props);
// 事件监听处理函数,this坏境的绑定
this.handleDelete = this.handleDelete.bind(this);
}
Решите проблему, связанную с тем, что обработчик событий каждый раз повторно отображается
В Es5 при вызове функции к имени функции часто нужно добавлять скобки, а при привязке функции-обработчика событий к элементу React в JSX принято добавлять ее, если не внимательно.
Это приведет к тому, что эта функция будет вызываться каждый раз при рендеринге компонента, что приведет к ненужному рендерингу функции рендеринга, что вызовет проблемы с производительностью.
Он должен обеспечить, чтобы, когда функция передачи на компонент не сразу же вызывает эту функцию, как показано ниже
render(){
return (
<button onClick = { this.handleClick()}>button</button>
);
}
Правильно сделать так, чтобы сама функция события (без круглых скобок) передавалась следующим образом
render(){
<button onClick = { this.handleClick }>button</button>
}
Далее представлены ключевые моменты этого раздела: я слышал о функциях дросселирования и защиты от сотрясений, но не совсем понимаю их.
Как предотвратить слишком быстрый вызов функции (регулирование функции) или слишком много раз (устранение дребезга функции)
Иногда, когда пользователи часто взаимодействуют с операциями интерфейса пользовательского интерфейса, такими как: настройка окна (запуск изменения размера), прокрутка страницы, загрузка подтягиваний (запуск прокрутки), отправка форм кнопками, сумасшедшие клики в торговых центрах (запуск mousedown) и Real поиск по времени (нажатие клавиши, ввод), перетаскивание и т. д.
Когда вы часто запускаете пользовательский интерфейс, обработчик событий будет запускаться постоянно, другими словами, когда есть непрерывные клики, подтягивающая загрузка, поиск в реальном времени, частые операции с элементами DOM и запросы на загрузку ресурсов, требовательные к производительности. операции, Это может привести к зависанию интерфейса, сбою браузера, пустой странице и т. д.
И чтобы решить эту проблему, есть функция троттлинга и функция анти-встряски.
регулирование функции определение: Сохранить (уменьшить) частоту срабатывания функций обработки событий и непрерывно запускать выполнение функций через равные промежутки времени.Это средство оптимизации высокочастотного выполнения фрагмента кода js.
Функции: Независимо от того, как часто событие запускается, оно гарантирует, что обработчик события действительно выполняется один раз в течение указанного интервала.
Сценарии применения: обычно используется для события щелчка мышью несколько раз подряд, перемещения мыши, перемещения мыши, перетаскивания, изменения размера окна (изменения размера), подтягивания страницы колесиком мыши (onScroll), подтягивания, обновления отложенной загрузки.
принцип: Запустите функцию, оценив, достигает ли она определенного времени, если нет указанного времени, используйте таймер для задержки, и следующее событие сбросит таймер, который является интервалом времени выполнения.
Операции, которые обычно связаны с высокой частотой в пользовательском интерфейсе:
- Страница колеса мыши подтягивается вверх (onScroll), тянется вниз, чтобы обновить ленивую загрузку
- Изменение размера окна (onresize)
- тянуть
Если это высокочастотная операция, если определенная обработка не выполняется, это неизбежно вызовет многократные запросы данных и нагрузку на сервер, поэтому производительность кода очень неэффективна, что влияет на производительность, и важным средством для уменьшения этого частого Операция заключается в снижении частоты с помощью дроссельного управления, то есть позволяет коду основной функции выполняться один раз в определенное время и как долго
Дросселирование должно гарантировать, что основной код выполняется только один раз за определенный период времени.
Примеры, которые можно связать с водосбережением в жизни (множество водозаборов на плотине «Три ущелья»):
Высокочастотные события подобны широко открытому крану, и вода вытекает в больших количествах, так же, как код постоянно выполняется, и если его не контролировать, это приведет к пустой трате ресурсов.
На соответствующей странице, если кнопка отправки постоянно нажимается в форме, отслеживается событие прокрутки, и запрашиваются ресурсы сервера для непрерывной загрузки раскрывающегося списка.
Чтобы задушить, закрутите кран, уменьшите частоту его потока воды и время от времени капайте каплю воды, тем самым экономя ресурсы.
Воплощение в коде: установите таймер, пусть код основной функции, сегмент отсека для выполнения
Ниже представлено колесо мыши, реализована дроссельная операция: аналогично непрерывной работе, все то же самое, непрерывно нажимайте кнопку, подтягивайте, чтобы загрузить Метод регулирования 1: отметка времени + таймер
/* throttle1函数,节流实现方式1:时间戳+定时器
* @params method,duration 第一个参数为事件触发时的真正要执行的函数
* 第二个参数duration表示为定义的间隔时间
*
* 原理:通过判断是否达到一定的时间来触发函数,若没有规定时间则使用计时器进行延迟,而下一次事件则会重新设定计时器,它是间隔时间执行,不管事件触发有多频繁,都会保证在规定内的事件一定会执行一次真正事件处理函数
*
* */
function throttle1(method, duration) {
var timer = null;
var prevTime = new Date(); // 之前的时间
return function() {
var that = this,
currentTime = new Date(), // 获取系统当前时间
resTime = currentTime - prevTime; // 时间戳
// 打印本次当前的世间和上次世间间隔的时间差
console.log("时间差", resTime);
// 当前距离上次执行时间小于设置的时间间隔
if(resTime < duration) {
// 清除上次的定时器,取消上次调用的队列任务,重新设置定时器。这样就可以保证500毫秒秒内函数只会被触发一次,达到了函数节流的目的
clearTimeout(timer);
timer = setTimeout(function(){
prevTime = currentTime;
method.apply(that);
}, duration)
}else { // 当前距离上次执行的时间大于等于设置的时间时,直接执行函数
// 记录执行方法的时间
prevTime = currentTime;
method.apply(that);
}
}
}
// 事件触发的方法(函数),函数节流1
function handleJieLiu1(){
console.log("节流方式1");
}
var handleJieLiu1 = throttle1(handleJieLiu1, 500);
document.addEventListener('mousewheel', handleJieLiu1);
Второй метод дросселирования:
/*
* throttle2函数节流实现方式2:重置一个开关变量+定时器
* @params method,duration形参数与上面的含义一致
* @return 返回的是一个事件处理函数
*
* 在throttle2执行时定义了runFlag的初始值,通过闭包返回一个匿名函数作为事件处理函数,
*
* 在返回的函数内部判断runFlag的状态并确定执行真正的函数method还是跳出,每次执行method后会更改runFlag的状态,通过定时器在durtion该规定的间隔时间内重置runFlag锁的状态
*
*/
function throttle2(method, duration){
// 当前时间间隔内是否有方法执行,设置一个开关标识
var runFlag = false;
// 返回一个事件处理函数
return function(e) {
// 判断当前是否有方法执行,有则什么都不做,若为true,则跳出
if(runFlag){
return false;
}
// 开始执行
runFlag = true;
// 添加定时器,在到达时间间隔时重置锁的状态
setTimeout(function(){
method(e);
// 执行完毕后,声明当前没有正在执行的方法,方便下一个时间调用
runFlag = false;
}, duration)
}
}
// 事件触发的方法(函数),函数节流2
function handleJieLiu2(){
console.log("节流方式2");
}
var handleJieLiu2 = throttle2(handleJieLiu2, 500);
document.addEventListener('mousewheel', handleJieLiu2);
Вышеуказанные два способа реализации регулирования функций могут предотвратить повторный запрос пользователями ресурсов из-за частых операций.
Конкретный эффект заключается в следующем:
В приведенном выше примере эффекта, когда колесо мыши продолжает прокручиваться, порядок выполнения обработчиков событий отличается.
При задании большого диапазона времени, например: в течение 1 часа, она будет выполняться каждые несколько минут, и не будет выполняться более часа, рекомендуется использовать первый способ регулирования функции.
Если требуется однократное выполнение с определенным интервалом, рекомендуется использовать второй способ дросселирования функции.
Функция защиты от тряски
определение: предотвратить тряску,Повторяющиеся триггеры, частые операции, суть в том, что выполнение обработчика события задерживается, и только последняя операция выполняется в течение определенного интервала времени, например: форма отправлена несколько раз, рекомендуется использовать защиту от встряхивания
Другими словами, обработчик события не выполняется, когда событие срабатывает непрерывно, выполняется только последний раз, когда оно срабатывает непрерывно на определенном этапе, это следует двум условиям.
- нужно немного подождать
- Временной интервал последнего триггера должен быть больше установленного значения для выполнения
Функции: Выполнять только один раз в определенный период времени В жизни вы можете себе представить, что водитель автобуса ждет, пока кто-то сядет в автобус, прежде чем покинуть станцию.
Сценарии применения: часто используется в событиях поля ввода keydown, keyup, прогнозирование поиска, только когда пользователь прекращает ввод с клавиатуры, отправляется запрос Ajax.
принцип: Он поддерживает таймер, который предусматривает, что функция обработки события запускается по истечении времени продолжительности (задержки), но если она снова запускается в течение времени продолжительности, текущий таймер будет очищен и пересчитан, так что только последняя операция событие обрабатывается Функция фактически запущена
Конкретный код выглядит следующим образом:
/*
* 函数防抖
* 例如:假定时间间隔时500ms,频繁不同的操作5s,且每两次执行时间小于等于间隔500ms
* 那么最后只执行了1次,也就是每一次执行时都结束上一次的执行
* @params method,duration,与上面一致
*
* 原理:它是维护一个计时器,规定在duration时间后出发时间处理函数,但是在duration时间内再次出发的化,都会清除当前的timer重新计时,这样一来,只有最后一次操作事件处理函数才被真正的触发
*
* 一般用于输入框事件,常用场景就是表单的搜索或者联想查询,如果不使用防抖会连续发送请求,增加服务器的压力,使用防抖后,会在用户输入要查询的关键词后才发送请求,百度搜索就是这么实现的
*
*
*/
function debounce(method, duration) {
var timer = null;
return function(){
var that = this,
args = arguments;
// 在本次调用之间的一个间隔时间内若有方法在执行,则终止该方法的执行
if(timer) {
clearTimeout(timer);
}
// 开始执行本次调用
timer = setTimeout(function(){
method.apply(that,args);
}, duration)
}
}
// 事件触发的方法(函数),防抖
function handleFangDou(){
console.log("函数的防抖",new Date());
}
var handleFangDou = debounce(handleFangDou, 500);
var oInput = document.querySelector("#input"); // 获取input元素
oInput.addEventListener('keyup',handleFangDou);
Конкретный эффект заключается в следующем:
Как показано в приведенном выше эффекте поля ввода, всякий раз, когда вводится поле ввода, когда появляется клавиатура, выполняется обработчик события, а не при вводе содержимого.Точно так же поисковые системы и функции прогнозирования формы не выполняют запросы данных Ajax на основе букв, цифр и содержимого, вводимого пользователем одновременно.Если запрос данных инициируется каждый раз, когда набирается буква, он потреблять производительность.
Запрос запроса должен срабатывать, когда пользователь перестает печатать, в это время используется функция защиты от встряхивания.
Множественная отправка форм, поиск Baidu и т. д. реализованы с защитой от сотрясений.резюме:
точки соприкосновения: Оба решают проблемы с производительностью, такие как частые операции, запускающие функции обработки событий, вызывающие зависание страницы и неравномерность.Они оба повышают производительность, устанавливая логику таймера задержки для уменьшения количества HTTP-запросов и экономии ресурсов запросов.разница: Функция throttling, функция обработки событий выполняется в пределах интервала, в то время как функция защиты от сотрясений выполняется только последняя операция в течение определенного интервала времени
Итак, как в React реализовать функцию дросселирования и функцию защиты от сотрясений?
Позаимствовал один в Reactloadsh.throttle
В библиотеке реализовано дросселирование функций
Сначала вам нужно установить библиотеку через npm или cnpm в терминале командной строки.
cnpm i -S lodash.throttle
Затем введите его в написанный вами компонент React и вызовите функцию дросселя, Этот дроссель получает два параметра, первый параметр — это обработчик события, который должен быть запущен, а второй — время задержки, которое вызывается каждые несколько секунд.
Ниже приведен код регулирования функции, его нельзя вызывать более одного раза в заданное время, а обработчик события щелчка можно вызывать только один раз в секунду.
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
import throttle from 'lodash.throttle'; // 引入lodash.throttle库
class LoadMoreButton extends Component {
constructor(props) {
super(props);
this.state = {
tip: '',
trigerTimes: 1
}
this.handleClick = this.handleClick.bind(this);
this.handleClickThrottled = throttle(this.handleClick, 1000); // 将触发事件处理函数作为第一个参数传入,第二个参数为间隔的时间,这里是1秒
}
componentWillUnmount() {
this.handleClickThrottled.cancel();
}
render() {
return(
<Fragment>
<div><button onClick={ this.handleClickThrottled }>Load More</button></div>
<div>{ this.state.tip }</div>
</Fragment>
)
}
handleClick() {
this.setState({
tip: `加载按钮触发了: ${ this.state.trigerTimes }次`,
trigerTimes: this.state.trigerTimes+1
})
}
}
class Load extends Component {
constructor(props){
super(props);
}
render(){
return (
<Fragment>
<LoadMoreButton />
</Fragment>
);
}
}
const container = document.getElementById('root');
ReactDOM.render(<Load />, container);
Эффект следующий
Если вы не используетеlodash.throttled
Сторонняя библиотека реализует троттлинг функций, аналогично также можно инкапсулировать троттлинг отдельно для реализации троттлинга функций, например:
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
class LoadMoreButton extends Component {
constructor(props) {
super(props);
this.state = {
tip: "",
trigerTimes: 1
}
this.handleLoadTime = this.handleLoadTime.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleClickThrottled = this.throttle(this.handleClick, 1000); // 将触发事件处理函数作为第一个参数传入,第二个参数为间隔的时间,这里是1秒
}
render() {
return(
<Fragment>
<div><button onClick={ this.handleClickThrottled }>Load More</button></div>
<div>{ this.state.tip }</div>
</Fragment>
)
}
handleLoadTime(){
// this.setState((prevState) => ({
// tip: `加载按钮触发了: ${prevState.trigerTimes}次`,
// trigerTimes: prevState.trigerTimes+1
// }))
// 等价于下面的
this.setState({
tip: `加载按钮触发了: ${ this.state.trigerTimes }次`,
trigerTimes: this.state.trigerTimes+1
})
}
// 事件处理函数
handleClick() {
this.handleLoadTime();
}
// 核心函数节流代码实现
throttle(method, duration){
// 当前时间间隔内是否有方法执行,设置一个开关标识
var runFlag = false;
// 返回一个事件处理函数
return function(e) {
// 判断当前是否有方法执行,有则什么都不做,若为true,则跳出
if(runFlag){
return false;
}
// 开始执行
runFlag = true;
// 添加定时器,在到达时间间隔时重置锁的状态
setTimeout(function(){
method(e);
// 执行完毕后,声明当前没有正在执行的方法,方便下一个时间调用
runFlag = false;
}, duration)
}
}
}
class Load extends Component {
constructor(props){
super(props);
}
render(){
return (
<Fragment>
<LoadMoreButton />
</Fragment>
);
}
}
const container = document.getElementById('root');
ReactDOM.render(<Load />, container);
Вы можете попробовать не добавлять функцию дросселя в стороннюю библиотеку lodash.throttled и не инкапсулировать функцию дросселя, вы обнаружите, что когда вы нажимаете кнопку, сколько раз вы нажимаете подряд, она будет непрерывно запускать функция обработчика событий, если это кнопка отправки формы, использующая регулирование функции для оптимизации кода
Последствия отказа от добавления функции дросселирования: следующие:
Если это кнопка отправки формы, сколько раз вы нажимаете на запрос к серверу, это, очевидно, проблема, если вы используете регулирование функции, чтобы очень хорошо решить эту проблему.После разговора о троттлинге функций React, как реализовать функцию защиты от сотрясения? Аналогично, React может использовать стороннюю библиотекуloadsh.debounce
реализовать
Вам все равно придется устанавливать сторонние библиотеки через npm или cnpm или yarn под терминал
npm i -S loadsh.debounce
或者
cnpm install -S loadsh.debounce
Независимо от того, установлен он или нет, вы можете проверить, есть ли loadsh.debounce в зависимостях в pageckage.json в корневом каталоге.
Давайте посмотрим на пример поля ввода для проверки номера мобильного телефона: Нижеследующее без использования функции анти-встряхивания Пример кода выглядит следующим образом:
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
class SearchBox extends Component{
constructor(props){
super(props)
this.state = {
tip: null,
trigerTimes: 1
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(e){
if(e.target.value){
this.setState({
tip: null
})
}
}
handleKeyUp = (e) => {
if(e.target.value){
this.isPhoneLegal(e.target.value) // 对用户输入进行判断
}
}
isPhoneLegal = (phone) => {
const phoneRegexp = /^1([38]\d|5[0-35-9]|7[3678])\d{8}$/
const { trigerTimes } = this.state
if(phoneRegexp.test(phone)) {
this.setState({
tip: `手机号符合规则!`,
trigerTimes: 0
})
} else {
this.setState({
tip: `手机号有误, 触发了:${trigerTimes}次`,
trigerTimes: trigerTimes + 1
})
}
// 这里发送Ajax请求
}
render() {
return (
<Fragment>
<div><input onChange = { this.handleChange } onKeyUp={ this.handleKeyUp} placeholder="请输入手机号" /></div>
<div >
{this.state.tip}
</div>
</Fragment>
)
}
}
class Search extends Component{
render(){
return (
<Fragment>
<SearchBox />
</Fragment>
);
}
}
const container = document.getElementById('root');
ReactDOM.render(<Search />, container);
Без защиты от сотрясений каждый раз, когда всплывает клавиша клавиатуры, она срабатывает один раз, и пользователю будет предложено, что ввод неверен, прежде чем ввод будет завершен.Этот опыт не очень хорош.
Другими словами, если запрос Ajax отправляется каждый раз, когда всплывает клавиатура, эта идея верна, но если интервал очень короткий, непрерывный ввод и запросы Ajax всегда отправляются часто, это приведет к появлению карточек страниц. давление на стороне сервера
Пример эффекта выглядит так:
Ниже приведена функция debounce, использующая функцию debounce. Пример кода показан ниже
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
//import throttle from 'lodash.throttle'; // 函数节流
import debounce from 'lodash.debounce'; // 函数防抖
class SearchBox extends Component{
constructor(props){
super(props)
this.state = {
tip: null,
trigerTimes: 1
}
this.handleChange = this.handleChange.bind(this);
this.isPhoneLegal = debounce(this.isPhoneLegal, 1000)
}
componentWillUnmount(){
this.isPhoneLegal.cancel();
}
handleChange(e){
if(e.target.value){
this.setState({
tip: null
})
}
}
handleKeyUp = (e) => {
if(e.target.value){
this.isPhoneLegal(e.target.value) // 对用户输入进行判断
}
}
isPhoneLegal = (phone) => {
const phoneRegexp = /^1([38]\d|5[0-35-9]|7[3678])\d{8}$/
const { trigerTimes } = this.state
if(phoneRegexp.test(phone)) {
this.setState({
tip: `手机号符合规则!`,
trigerTimes: 0
})
} else {
this.setState({
tip: `手机号有误, 触发了:${trigerTimes}次`,
trigerTimes: trigerTimes + 1
})
}
// 这里发送Ajax请求
}
render() {
return (
<Fragment>
<div><input onChange = { this.handleChange } onKeyUp={ this.handleKeyUp} placeholder="请输入手机号" /></div>
<div >
{this.state.tip}
</div>
</Fragment>
)
}
}
class Search extends Component{
render(){
return (
<Fragment>
<SearchBox />
</Fragment>
);
}
}
const container = document.getElementById('root');
ReactDOM.render(<Search />, container);
Конечно, вы не используете для устранения дребезга функцию debounce, предоставляемую библиотекой lodash.debounce.Также можно инкапсулировать debounce нативным способом, как описано выше. Код следующий: нужно только изменить deboucunce обработчика событий этой среды, а остальные коды такие же, как и раньше
this.isPhoneLegal = this.debounce(this.isPhoneLegal, 1000)
Обратите внимание, что в настоящее время функция устранения дребезга в этой сборке searchBox может, если разница небольшая, обратите внимание на функцию устранения дребезга во внешнем компоненте, прямое использование функции, определенной декларативно, имя функции прямого вызова debouce, общее для таких функций, может быть отдельно инкапсулирован в файл можно перейти
Соберите их в свои общие библиотеки, чтобы избежать таких анти-встряхивающих функций, разбросанных в различных файлах, повсюду, и функционируйте, также функционируют. Ниже приведен инкапсуляция функции отборочных анти-встряхивания
// 自己封装一个debounce函数用于防抖
debounce(method, duration) {
var timer = null;
/*return function(){
var that = this,
args = arguments;
// 在本次调用之间的一个间隔时间内若有方法在执行,则终止该方法的执行
if(timer) {
clearTimeout(timer);
}
// 开始执行本次调用
timer = setTimeout(function(){
method.apply(that,args);
}, duration)
}*/
// 上面的return匿名函数可以用Es6的箭头函数,以下写法与上面等价,最简洁的写法,但是没有上面的代码好理解
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => method(...args), duration)
}
}
Конечно, приведенный выше код все еще можно оптимизировать.Для функции обратного вызова в Es6 он часто используется для обработки стрелочной функции, что избавит от многих проблем. Например: это указывает на вопрос Как показано ниже: Простейшая инкапсуляция функции debouce
Вы также можете поместить вышеуказанное начальное значение таймера в функцию debouce в качестве третьей настройки параметра, это также возможно
debounce(method, duration, timer = null) {
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
method(...args)
}, duration)
}
}
Если вы инкапсулируете его самостоятельноthrottle
а такжеdebounce
Функции могут быть индивидуально инкапсулированы в файл и выставлены внешнему миру, там, где они нужны, их можно импортировать через импорт, и их можно вызывать непосредственно в коде.
Создайте дроссель.js в корневом каталоге (в зависимости от того, какой у вас есть)
выставлен через экспорт по умолчанию
/*
* @authors 川川 (itclancode@163.com)
* @ID suibichuanji
* @date 2019-08-24 19:08:17
* @weChatNum 微信公众号:itclancoder
@desc 封装节流函数
* @param method,duration:method事件处理函数,duration:间隔的时间
* @return 匿名函数
* 原理: 通过判断是否达到一定的时间来触发函数,
* 若没有规定时间则使用计时器进行延迟,而下一次事件则会重新设定计时器
* 它是间隔时间执行,不管事件触发有多频繁
* 都会保证在规定内的事件一定会执行一次真正事件处理函数
*
*/
function throttle(method, duration) {
var timer = null;
var prevTime = new Date(); // 之前的时间
return function() {
var that = this,
currentTime = new Date(), // 获取系统当前时间
resTime = currentTime - prevTime; // 时间戳
// 打印本次当前的世间和上次世间间隔的时间差
console.log("时间差", resTime);
// 当前距离上次执行时间小于设置的时间间隔
if (resTime < duration) {
// 清除上次的定时器,取消上次调用的队列任务,重新设置定时器。这样就可以保证500毫秒秒内函数只会被触发一次,达到了函数节流的目的
clearTimeout(timer);
timer = setTimeout(function() {
prevTime = currentTime;
method.apply(that);
}, duration)
} else { // 当前距离上次执行的时间大于等于设置的时间时,直接执行函数
// 记录执行方法的时间
prevTime = currentTime;
method.apply(that);
}
}
}
export default throttle;
Затем введите его в файл, который должен использовать регулирование функции.
import throttle from './throttle';
// 在组件的constructor内初始化,this坏境绑定处进行调用
this.handleClickThrottled = throttle(this.handleClick, 1000);
Точно так же, если вы сами инкапсулируете функцию защиты от сотрясений функции устранения дребезга, извлеките ее отдельно и инкапсулируете в функцию, а также выставите ее во внешний мир через экспорт для других мест для вызова
/**
*
* @authors 川川 (itclancode@163.com)
* @ID suibichuanji
* @date 2019-08-24 19:08:17
* @weChatNum 微信公众号:itclancoder
* @version $Id$
* @description 函数防抖
* @param { method, duration} [method是事件处理函数,duration是延迟时间]
* 原理
* 原理:它是维护一个计时器,规定在duration时间后出发时间处理函数
* 但是在duration时间内再次出发的化,都会清除当前的timer重新计时
* 这样一来,只有最后一次操作事件处理函数才被真正的触发
*
* 一般用于输入框事件,常用场景就是表单的搜索或者联想查询,
* 如果不使用防抖会连续发送请求,增加服务器的压力
* 使用防抖后,会在用户输入要查询的关键词后才发送请求,百度搜索就是这么实现的
*/
function debounce(method, duration) {
var timer = null;
return function(){
var that = this,
args = arguments;
// 在本次调用之间的一个间隔时间内若有方法在执行,则终止该方法的执行
if(timer) {
clearTimeout(timer);
}
// 开始执行本次调用
timer = setTimeout(function(){
method.apply(that,args);
}, duration)
}
}
export default debounce;
резюме:
Как дросселировать и устранять дребезг в React
- Относится к функции дросселя сторонней библиотеки lodash.throttle.
- Инкапсулируйте функцию дросселя самостоятельно для дросселирования
- Относится к функции debounce библиотеки lodash.debounce Desan.
- Инкапсулируйте функцию устранения дребезга самостоятельно для защиты от сотрясений
Суммировать
Вся статья начинается с введения в события React, объектов событий (событий), сравнения производительности привязки, передачи параметров обработчикам событий и, наконец, того, как предотвратить слишком быстрые вызовы функций (дросселирование функции, два способа) или слишком много раз. (функция anti-shake), реализованная соответственно нативными JS и сторонними библиотеками в React
Дросселирование и защита от встряхивания функций являются средствами повышения производительности внешнего интерфейса.Хотя это всего несколько строк кода, во время собеседования вас часто просят написать от руки.Много раз вы не можете быть в состоянии сделать это без поиска. может написать
В реальных разработках функции дросселирования и функции защиты от сотрясений также встречаются относительно часто, поэтому их важность очевидна.