Re[3]: [React] Хитрый реакт не триггерит onChange у инпутов?
От: vsb Казахстан  
Дата: 02.09.19 08:57
Оценка: 10 (1)
Здравствуйте, VladCore, Вы писали:

VC>не. я тут посмотрел у Event нет такого конструктора какой у них: https://developer.mozilla.org/ru/docs/Web/API/Event

VC>Где они нашли его? :https://developer.mozilla.org/ru/docs/Web/API/Event/Event

Вот же он: https://developer.mozilla.org/en-US/docs/Web/API/Event/Event

VC>Ну и ЗАЧЕМ они вместо inpit.value = ........ пищут (хотя прямой вызов input.value = 'не работает' не работает)

VC>
VC>var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
VC>nativeInputValueSetter.call(input, 'is working');
VC>


В статье написано. React переопределяет setter для свойства value. А они "родной" используют, который бы вызывался без React. Я так понимаю, что в родной реализации как раз вызываются нужные события, которые потом React ловит и обрабатывает. А React-овская реализация эти события не вызывает (видимо для скорости).

VC>Стремно как то попахивает.


Лишь бы работало. Хочешь не стрёмно — делай всё через React, как положено.
[React] Хитрый реакт не триггерит onChange у инпутов?
От: VladCore  
Дата: 31.08.19 06:13
Оценка:
Поясню.

Вот есть обычный managed input, т.е. value={this.state.name} onchange{(event) => this.setState({name:event.target.value}}

И вот этот onchange, гад, вызывается похоже только в onKeyDown

если поменять значение через стандартно через DOM, то onchange не вызывается и state не меняется.
Овно короче

Вот тут легко воспроизводтся:
https://edwardfhsiao.github.io/react-inputs-validation/

Скроллим на форму в конце.
в консоли вводим
document.getElementById('Name').value='James';

Видим что поле поменялось на форме.

Что бы убедится, что в state поле пустое, просто щелкаем по полю Name и потом по другому полю.
Видим красную invalid-подсказку: Name cannot be empty


Вот и скриншот даже сделал


Временное решение

Я сделал через задницу после того как прочитал тут: https://ru.reactjs.org/docs/forms.html

А так как каждое нажатие клавиши вызывает handleChange, который обновляет состояние React-компонента, значение в поле будет обновляться по мере того, как пользователь печатает.


То я сделал смену значения инпута через задницу:
const setValue = async (selector, value) => {
    await context.evaluate(`document.getElementById('${selector}').focus()`);
    await context.evaluate(`document.getElementById('${selector}').select()`);
    for(let c of value) await context.Protocol.Input.dispatchKeyEvent({type:"keyDown", text:String(c)});
};


Но так не будет, я подозреваю, работать юникодные символы, Капсы, да и если текста надо 1M вбить то это растянется на вечность.

Помогите
Как сделать что бы
input.value = 'James';

заработало.
Точнее что бы реакт увидел новые значения. оставить временное решение тоже нельзя. нужно что бы любые значение можно было задавать, включая емоджи и не по одному символу за раз.

у метода dispatchKeyEvent на самом деле дофига параметров. Может он как то умеет сразу весь текст передавать но этого не понять

Единственное что я пробовал и оно не работает:
input.focus()
input.value='James';
input.blur();



P.S. я работаю через штатный удаленный отладчик хрома, но это совершенно не важно. Просто что бы не пугались моего временного решения.
В самом реакт-приложении я таким способом менять значение полей ввода я конечно не собираюсь.
Отредактировано 31.08.2019 6:37 VladCore . Предыдущая версия . Еще …
Отредактировано 31.08.2019 6:35 VladCore . Предыдущая версия .
Отредактировано 31.08.2019 6:32 VladCore . Предыдущая версия .
Отредактировано 31.08.2019 6:31 VladCore . Предыдущая версия .
Re: [React] Хитрый реакт не триггерит onChange у инпутов?
От: Ops Россия  
Дата: 31.08.19 07:55
Оценка:
Здравствуйте, VladCore, Вы писали:

VC>Скроллим на форму в конце.

VC>в консоли вводим
VC>
VC>document.getElementById('Name').value='James';
VC>

VC>Видим что поле поменялось на форме.

VC>Что бы убедится, что в state поле пустое, просто щелкаем по полю Name и потом по другому полю.

VC>Видим красную invalid-подсказку: Name cannot be empty

А если
document.getElementById('Name').dispatchEvent(new Event('change'));

?

ЗЫ. Это не реакт, это браузер не генерирует событий при изменении value из кода.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Отредактировано 31.08.2019 8:04 ути-пути . Предыдущая версия .
Re[2]: [React] dispatchKeyEvent рулит. Но как нажать DEL или
От: VladCore  
Дата: 01.09.19 21:27
Оценка:
Здравствуйте, Ops, Вы писали:

Я сначала думал что dispatchKeyEvent не сможет "эмулировать" нажатие юникодных символов но это не так. Они правильно передаются в параметре text.
и в цикле его не нужно вызывать по одной букве за раз.

Единственная проблема если новое значение пустое, то старый текст просто выделяется весь, но text="" старое значение не удаляет.
Как передать DEL или BACKSPACE?

Ops>А если

Ops>
Ops>document.getElementById('Name').dispatchEvent(new Event('change'));
Ops>

Ops>?

Это что то не ты ты написал.

Дело не в том что в конструкторе нету параметра type
В ивенте надо не только тип но и остальные свойства — как минимум target.value
Во вторых наверно все же не type="change" а type=input с действием keydown и кодом клавиши, которое текущая внутренняя реализация маппит на SyntheticEvent с type="change" и target.value.

Вот эта привязка к реализации реакта мне и не нравится.

В третьих текущая реализация реакта в обработчике ивента трекает внутри предыдущее полное значение — в результате мешанина получается если задавать значение через input.value и потом досылать dispatchEvent вызовы.

А так input.focus() выделяет всё в input и потом первое нажатие клавиш удаляет всё предыдущее значение.
Если нужно пустое значение — это не будет работать. Надо как то backspace сначала послать. Вот в чем единственная проблема.



Ops>ЗЫ. Это не реакт, это браузер не генерирует событий при изменении value из кода.


Отредактировано 01.09.2019 21:38 VladCore . Предыдущая версия .
Re: [React] Хитрый реакт не триггерит onChange у инпутов?
От: vsb Казахстан  
Дата: 01.09.19 21:31
Оценка:
Первую ссылку из гугла пробовал?
Re[3]: [React] dispatchKeyEvent не так уж и плох. Но как нажать DEL или Backspac
От: Ops Россия  
Дата: 01.09.19 21:48
Оценка:
Здравствуйте, VladCore, Вы писали:

VC>Это что то не ты ты написал.


Да вроде все то, выполняем на сайте по твоей ссылке эти 2 строчки, получаем искомый результат, без всяких плясок с эмуляцией ввода.
document.getElementById('Name').value='James';
document.getElementById('Name').dispatchEvent(new Event('change'));

Никакой красной invalid-подсказки, можешь сам попробовать. Может этот сайт с примером не похож на твой реальный код? Что не работает-то?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: [React] Хитрый реакт не триггерит onChange у инпутов?
От: VladCore  
Дата: 01.09.19 21:48
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Первую ссылку из гугла пробовал?


не. я тут посмотрел у Event нет такого конструктора какой у них: https://developer.mozilla.org/ru/docs/Web/API/Event
Где они нашли его?

Ну и ЗАЧЕМ они вместо inpit.value = ........ пищут (хотя прямой вызов input.value = 'не работает' не работает)
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'is working');


И почему в input-event не передают код клавиши?
var inputEvent = new Event('input', { bubbles: true});
input.dispatchEvent(inputEvent);


Стремно как то попахивает.
Отредактировано 01.09.2019 22:04 VladCore . Предыдущая версия .
Re[4]: [React] dispatchKeyEvent не так уж и плох. Но как наж
От: VladCore  
Дата: 01.09.19 21:57
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>Здравствуйте, VladCore, Вы писали:


VC>>Это что то не ты ты написал.


Ops>Да вроде все то, выполняем на сайте по твоей ссылке эти 2 строчки, получаем искомый результат, без всяких плясок с эмуляцией ввода.

Ops>
Ops>document.getElementById('Name').value='James';
Ops>document.getElementById('Name').dispatchEvent(new Event('change'));
Ops>

Ops>Никакой красной invalid-подсказки, можешь сам попробовать. Может этот сайт с примером не похож на твой реальный код? Что не работает-то?

У тебя какой браузер? В хроме Version 76.0.3809.132 (Official Build) (64-bit) не работает



Может ему надо bubble:true указать как у vsb? сейчас проверю
Отредактировано 01.09.2019 21:58 VladCore . Предыдущая версия .
Re[5]: [React] dispatchKeyEvent не так уж и плох. Но как наж
От: Ops Россия  
Дата: 01.09.19 22:26
Оценка:
Здравствуйте, VladCore, Вы писали:

VC>У тебя какой браузер? В хроме Version 76.0.3809.132 (Official Build) (64-bit) не работает


ФФ. Проверил в хроме — действительно не пашет.
Только оно чего-то и при вводе с клавиатуры как-то нестабильно работает.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Отредактировано 01.09.2019 22:29 ути-пути . Предыдущая версия .
Re[6]: [React] Ответ с dispatchKeyEvent
От: VladCore  
Дата: 02.09.19 00:15
Оценка:
Здравствуйте, Ops, Вы писали:

VC>>У тебя какой браузер? В хроме Version 76.0.3809.132 (Official Build) (64-bit) не работает


Ops>ФФ. Проверил в хроме — действительно не пашет.

Ops>Только оно чего-то и при вводе с клавиатуры как-то нестабильно работает.

Спасибо. Пашет то что нашел vsb с "перегрузкой" input.value. В хроме.

Мне надо удаленно и без перегрузки чего бы то нибыло в странице.

Финальный вариант с поддержкой Unicode, пустых значений и без циклов
const setValue = async (elementId, value) => {
    await context.getExpression(`document.getElementById('${elementId}').focus()`);
    await context.getExpression(`document.getElementById('${elementId}').select()`);
    // https://github.com/GoogleChrome/puppeteer/blob/master/lib/Input.js
    // https://javascript.info/keyboard-events
    const valueAsString = String(value);
    if (value === null || value === undefined || valueAsString.length === 0)
        // 8: Backspace, 46: Delete
        await context.Protocol.Input.dispatchKeyEvent({type:"rawKeyDown", windowsVirtualKeyCode:8});
    else
        await context.Protocol.Input.dispatchKeyEvent({type:"keyDown", text:valueAsString});
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.