Что является лучшим способом, чтобы вызвать событие onChange в реагировать JS
мы используем Backbone + ReactJS bundle для создания клиентского приложения.
Сильно полагаясь на пресловутый valueLink
мы распространяем значения непосредственно на модель через собственную оболочку, которая поддерживает интерфейс ReactJS для двухсторонней привязки.
теперь мы столкнулись с проблемой:
у нас есть jquery.mask.js
плагин, который форматирует входное значение программно, таким образом, он не запускает события реакции. Все это приводит к ситуации, когда модель получает неформатированный значения из пользовательского ввода и пропускает форматированные из плагина.
похоже, что React имеет множество стратегий обработки событий в зависимости от браузера. Есть ли какой-либо общий способ вызвать событие изменения для конкретного элемента DOM, чтобы React услышал его?
8 ответов:
для React 16 и React >=15.6
сеттер
.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
С
react-dom ^15.6.0
можно использоватьsimulated
флаг на объекте события для события, чтобы пройти черезvar ev = new Event('input', { bubbles: true}); ev.simulated = true; element.value = 'Something new'; element.dispatchEvent(ev);
чтобы понять, зачем нужен новый флаг я нашел комментарий очень полезная:
входной логики в теперь реагировал на происходящее изменение уровней, поэтому они не стреляют больше чем один раз в стоимость. Он слушает как браузер onChange/onInput события, а также наборы на опоре значения узла DOM (при обновлении значение через JavaScript). Это имеет побочный эффект означает, что если вы обновите значение ввода вручную.значение = ' foo ' затем отправить a ChangeEvent с { цель: ввод } реагировать будет зарегистрировать и установить и событие, см. Его значение по-прежнему "foo", считайте его дубликатом событие и проглотить его.
это прекрасно работает в нормальных случаи, потому что" реальный " браузер инициирован событие не вызывает наборы на элементе.значение. Вы можете выбраться из эта логика тайно помечает событие, которое вы запускаете с имитацией флаг и реагировать всегда будет стрелять событие. https://github.com/jquense/react/blob/9a93af4411a8e880bbc05392ccf2b195c97502d1/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js#L128
по крайней мере на текстовых входов, получается, что
onChange
прослушивает входные события:var event = new Event('input', { bubbles: true }); element.dispatchEvent(event);
Я знаю, что этот ответ немного поздно, но я недавно столкнулась с подобной проблемой. Я хотел вызвать событие на вложенном компоненте. У меня был список с виджетами типа radio и check box (они были divs, которые вели себя как флажки и/или переключатели), а в другом месте приложения, если кто-то закрыл панель инструментов, мне нужно было снять ее.
Я нашел довольно простое решение, не уверен, что это лучшая практика, но она работает.
var event = new MouseEvent('click', { 'view': window, 'bubbles': true, 'cancelable': false }); var node = document.getElementById('nodeMyComponentsEventIsConnectedTo'); node.dispatchEvent(event);
этот вызвал событие click на domNode, и мой обработчик, прикрепленный через react, действительно был вызван, поэтому он ведет себя так, как я ожидал бы, если бы кто-то нажал на элемент. Я не тестировал onChange, но он должен работать, и не уверен, как это будет справедливо в действительно старых версиях IE, но я считаю, что MouseEvent поддерживается по крайней мере в IE9 и выше.
Я в конечном итоге отошел от этого для моего конкретного случая использования, потому что мой компонент был очень маленьким (только часть моего приложения использовала react поскольку я все еще изучаю его), и я мог бы достичь того же самого другим способом, не получая ссылок на узлы dom.
обновление:
как уже сказали в комментариях, лучше использовать
this.refs.refname
чтобы получить ссылку на узел dom. В этом случае refname-это ссылка, которую вы прикрепили к своему компоненту через<MyComponent ref='refname' />
.
вы можете имитировать события с помощью ReactTestUtils но это предназначено для модульного тестирования.
Я бы рекомендовал не использовать valueLink для этого случая и просто слушать события изменения, запущенные плагином, и обновлять состояние ввода в ответ. Двусторонняя привязка utils больше как демонстрация, чем что-либо еще; они включены в аддоны только для того, чтобы подчеркнуть тот факт, что чистая двусторонняя привязка не подходит для большинства приложений и что вам обычно нужно больше логика приложения для описания взаимодействий в вашем приложении.
запуск событий изменения на произвольных элементах создает зависимости между компонентами, о которых трудно рассуждать. Лучше придерживаться одностороннего потока данных 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
ну так как мы используем функции для обработки события 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)} /> ); } }
расширяя ответ от 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); } };
Если вы используете позвоночник и реагируете, я бы рекомендовал одно из следующих,
Они оба помогают интегрировать базовые модели и коллекции с React views. Вы можете использовать события магистрали так же, как Вы делаете с представлениями магистрали. Я баловался обоими и не видел большой разницы, кроме одного-это mixin, а другие изменения
React.createClass
доReact.createBackboneClass
.