Ответ 1
По крайней мере, на текстовых входах, кажется, что onChange
прослушивает входные события:
var event = new Event('input', { bubbles: true });
element.dispatchEvent(event);
Добрый день.
Мы используем пакет backhone + reactjs для создания клиентского приложения. Сильно полагаясь на пресловутую ценностьLink, мы распространяем значения непосредственно на модель через собственную оболочку, которая поддерживает интерфейс js для двусторонней привязки.
Теперь мы столкнулись с проблемой:
У нас есть jquery.mask.js-плагин, который форматно вводит значение ввода, поэтому он не запускает события React. Все это приводит к ситуации, когда модель получает неформатированные значения от пользовательского ввода и пропускает отформатированные из плагина.
Кажется, что React имеет множество стратегий обработки событий в зависимости от браузера. Есть ли какой-либо общий способ инициировать событие изменения для конкретного элемента DOM, чтобы React его услышал?
По крайней мере, на текстовых входах, кажется, что onChange
прослушивает входные события:
var event = new Event('input', { bubbles: true });
element.dispatchEvent(event);
Я знаю, что этот ответ приходит немного поздно, но я недавно столкнулся с подобной проблемой. Я хотел вызвать событие на вложенном компоненте. У меня был список с виджетами типа "радио" и "флажок" (они были 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' />
.
Для 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
Вы можете имитировать события, используя ReactTestUtils, но предназначенные для модульного тестирования.
Я бы рекомендовал не использовать valueLink для этого случая и просто слушать события изменений, запускаемые плагином, и обновлять состояние ввода в ответ. Двунаправленное связывание используется как демо, чем что-либо еще; они включены в аддоны только для того, чтобы подчеркнуть тот факт, что чистая двусторонняя привязка не подходит для большинства приложений и что для описания взаимодействий в вашем приложении обычно требуется больше логики приложения.
Запуск событий изменения на произвольных элементах создает зависимости между компонентами, о которых трудно рассуждать. Лучше придерживаться одностороннего потока данных 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
Если вы используете Backbone и React, я бы рекомендовал один из следующих вариантов:
Они помогают интегрировать модели и коллекции Backbone с представлениями React. Вы можете использовать Backbone-события так же, как вы делаете с представлениями Backbone. Я играл в обоих случаях и не видел большой разницы, кроме одного - mixin, а другие изменения React.createClass
- React.createBackboneClass
.
так как мы используем функции для обработки события 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);
}
};