Подтвердить что ты не робот

Каков наилучший способ запуска события onchange в реакции js

Добрый день.

Мы используем пакет backhone + reactjs для создания клиентского приложения. Сильно полагаясь на пресловутую ценностьLink, мы распространяем значения непосредственно на модель через собственную оболочку, которая поддерживает интерфейс js для двусторонней привязки.

Теперь мы столкнулись с проблемой:

У нас есть jquery.mask.js-плагин, который форматно вводит значение ввода, поэтому он не запускает события React. Все это приводит к ситуации, когда модель получает неформатированные значения от пользовательского ввода и пропускает отформатированные из плагина.

Кажется, что React имеет множество стратегий обработки событий в зависимости от браузера. Есть ли какой-либо общий способ инициировать событие изменения для конкретного элемента DOM, чтобы React его услышал?

4b9b3361

Ответ 1

По крайней мере, на текстовых входах, кажется, что onChange прослушивает входные события:

var event = new Event('input', { bubbles: true });
element.dispatchEvent(event);

Ответ 2

Я знаю, что этот ответ приходит немного поздно, но я недавно столкнулся с подобной проблемой. Я хотел вызвать событие на вложенном компоненте. У меня был список с виджетами типа "радио" и "флажок" (они были divs, которые вели себя как флажки и/или переключатели), а в каком-то другом месте приложения, если кто-то закрыл панель инструментов, мне нужно было снять отметку с нее.

Я нашел довольно простое решение, не уверен, что это лучшая практика, но она работает.

var event = new MouseEvent('click', {
 'view': window, 
 'bubbles': true, 
 'cancelable': false
});
var node = document.getElementById('nodeMyComponentsEventIsConnectedTo');
node.dispatchEvent(event);

Это вызвало событие click на domNode, и мой обработчик, подключенный через реакцию, действительно был вызван так, что он ведет себя так, как я ожидал бы, если бы кто-то нажал на элемент. Я не тестировал onChange, но он должен работать, и не уверен, как это будет справедливо в действительно старых версиях IE, но я считаю, что MouseEvent поддерживается, по крайней мере, в IE9 и выше.

В конце концов я отошел от этого для моего конкретного случая использования, потому что мой компонент был очень маленьким (только часть моего приложения использовалась, так как я все еще его изучаю), и я мог бы достичь того же самого по-другому, не получая ссылок на dom.

UPDATE:

Как указывали другие комментарии, лучше использовать this.refs.refname для получения ссылки на dom node. В этом случае refname - это ссылка, которую вы привязали к своему компоненту через <MyComponent ref='refname' />.

Ответ 3

Для React 16 и React >= 15.6

Setter .value= работает не так, как хотелось бы, потому что библиотека React переопределяет параметр ввода значений, но мы можем вызвать функцию непосредственно в контексте input.

var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'react 16 value');

var ev2 = new Event('input', { bubbles: true});
input.dispatchEvent(ev2);

Для элемента textarea вы должны использовать prototype класса HTMLTextAreaElement.

Новый пример codepen.

Все кредиты этот вкладчик и его решение

Устаревший ответ только для React <= 15.5

С помощью react-dom ^15.6.0 вы можете использовать флаг simulated для объекта события для прохождения события через

var ev = new Event('input', { bubbles: true});
ev.simulated = true;
element.value = 'Something new';
element.dispatchEvent(ev);

Я сделал codepen с примером

Чтобы понять, зачем нужен новый флаг, я нашел этот комментарий очень полезным:

Входная логика в React теперь дедуплирует изменения, поэтому они не срабатывают более одного раза за значение. Он прослушивает оба браузера onChange/onInput события, а также наборы значений DOM node (при обновлении значение через javascript). Это имеет побочный эффект от значения, если вы обновите входное значение вручную input.value = 'foo', затем отправьте ChangeEvent с {target: input} React будет регистрировать как набор и событие, увидеть его значение по-прежнему `` foo ', считать его дубликат события и усвоить его.

Это нормально работает в обычных случаях, потому что инициирован "реальный" браузер событие не вызывает множества на элементе.значение. Вы можете выручить эту логику тайно, пометив событие, которое вы запускаете с помощью имитируемого флаг и реакция всегда будут запускать событие. https://github.com/jquense/react/blob/9a93af4411a8e880bbc05392ccf2b195c97502d1/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js#L128

Ответ 4

Вы можете имитировать события, используя ReactTestUtils, но предназначенные для модульного тестирования.

Я бы рекомендовал не использовать valueLink для этого случая и просто слушать события изменений, запускаемые плагином, и обновлять состояние ввода в ответ. Двунаправленное связывание используется как демо, чем что-либо еще; они включены в аддоны только для того, чтобы подчеркнуть тот факт, что чистая двусторонняя привязка не подходит для большинства приложений и что для описания взаимодействий в вашем приложении обычно требуется больше логики приложения.

Ответ 5

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

Нет никакого простого фрагмента, чтобы вызвать событие изменения React. Логика реализована в ChangeEventPlugin.js, и есть разные ветки кода для разных типов ввода и браузеров. Более того, детали реализации различаются в разных версиях React.

Я построил react-trigger-change, который делает это, но предназначен для тестирования, а не как зависимость производства:

let node;
ReactDOM.render(
  <input
    onChange={() => console.log('changed')}
    ref={(input) => { node = input; }}
  />,
  mountNode
);

reactTriggerChange(node); // 'changed' is logged

CodePen

Ответ 6

Если вы используете Backbone и React, я бы рекомендовал один из следующих вариантов:

Они помогают интегрировать модели и коллекции Backbone с представлениями React. Вы можете использовать Backbone-события так же, как вы делаете с представлениями Backbone. Я играл в обоих случаях и не видел большой разницы, кроме одного - mixin, а другие изменения React.createClass - React.createBackboneClass.

Ответ 7

так как мы используем функции для обработки события onchange, мы можем сделать это следующим образом:

class Form extends Component {
 constructor(props) {
  super(props);
  this.handlePasswordChange = this.handlePasswordChange.bind(this);
  this.state = { password: '' }
 }

 aForceChange() {
  // something happened and a passwordChange
  // needs to be triggered!!

  // simple, just call the onChange handler
  this.handlePasswordChange('my password');
 }

 handlePasswordChange(value) {
 // do something
 }

 render() {
  return (
   <input type="text" value={this.state.password} onChange={changeEvent => this.handlePasswordChange(changeEvent.target.value)} />
  );
 }
}

Ответ 8

Расширение ответа от Grin/Dan Abramov, это работает по нескольким типам ввода. Протестировано в React >= 15.5

const inputTypes = [
    window.HTMLInputElement,
    window.HTMLSelectElement,
    window.HTMLTextAreaElement,
];

export const triggerInputChange = (node, value = '') => {

    // only process the change on elements we know have a value setter in their constructor
    if ( inputTypes.indexOf(node.__proto__.constructor) >-1 ) {

        const setValue = Object.getOwnPropertyDescriptor(node.__proto__, 'value').set;
        const event = new Event('input', { bubbles: true });

        setValue.call(node, value);
        node.dispatchEvent(event);

    }

};