reactjs - react - ¿Cuál es la mejor manera de desencadenar el evento de cambio en reaccionar js
jsx element div has no corresponding closing tag (8)
Usamos el paquete Backbone + ReactJS para construir una aplicación del lado del cliente. valueLink
en valueLink
valores directamente al modelo a través de un envoltorio propio que admite la interfaz ReactJS para el enlace bidireccional.
Ahora enfrentamos el problema:
Tenemos el plugin jquery.mask.js
que formatea el valor de entrada mediante programación, por lo que no activa eventos Reaccionar. Todo esto conduce a una situación en la que el modelo recibe valores sin formato de la entrada del usuario y pierde los formateados del complemento.
Parece que React tiene muchas estrategias de manejo de eventos dependiendo del navegador. ¿Hay alguna forma común de desencadenar un evento de cambio para un elemento DOM particular para que React lo escuche?
Al menos en las entradas de texto, parece que onChange
está escuchando eventos de entrada:
var event = new Event(''input'', { bubbles: true });
element.dispatchEvent(event);
Ampliando la respuesta de Grin / Dan Abramov, esto funciona en múltiples tipos de entrada. Probado en 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);
}
};
Disparar eventos de cambio en elementos arbitrarios crea dependencias entre componentes que son difíciles de razonar. Es mejor seguir con el flujo de datos unidireccional de React.
No hay un fragmento simple para desencadenar el evento de cambio de React. La lógica se implementa en ChangeEventPlugin.js y existen diferentes ramas de código para diferentes tipos de entrada y navegadores. Además, los detalles de implementación varían según las versiones de React.
He creado react-trigger-change que hace la cosa, pero está destinado a ser utilizado para pruebas, no como una dependencia de producción:
let node;
ReactDOM.render(
<input
onChange={() => console.log(''changed'')}
ref={(input) => { node = input; }}
/>,
mountNode
);
reactTriggerChange(node); // ''changed'' is logged
Puede simular eventos usando ReactTestUtils pero eso está diseñado para pruebas unitarias.
Recomiendo no usar ValueLink para este caso y simplemente escuchar para cambiar los eventos activados por el complemento y actualizar el estado de la entrada en respuesta. El enlace bidireccional utiliza más como demostración que cualquier otra cosa; se incluyen en los complementos solo para enfatizar el hecho de que el enlace bidireccional puro no es apropiado para la mayoría de las aplicaciones y que generalmente necesita más lógica de aplicación para describir las interacciones en su aplicación.
Sé que esta respuesta llega un poco tarde, pero recientemente me enfrenté a un problema similar. Quería activar un evento en un componente anidado. Tenía una lista con widgets de tipo de casilla de verificación y de radio (eran divs que se comportaban como casillas de verificación y / o botones de radio) y en algún otro lugar de la aplicación, si alguien cerraba una caja de herramientas, necesitaba desmarcar una.
Encontré una solución bastante simple, no estoy seguro si esta es la mejor práctica, pero funciona.
var event = new MouseEvent(''click'', {
''view'': window,
''bubbles'': true,
''cancelable'': false
});
var node = document.getElementById(''nodeMyComponentsEventIsConnectedTo'');
node.dispatchEvent(event);
Esto desencadenó el evento click en domNode y mi controlador adjunto a través de reaccionar se llamó de hecho para que se comporte como lo esperaría si alguien hace clic en el elemento. No he probado onChange pero debería funcionar, y no estoy seguro de cómo será justo en versiones realmente antiguas de IE, pero creo que MouseEvent es compatible al menos con IE9 y versiones superiores.
Eventualmente me alejé de esto para mi caso de uso particular porque mi componente era muy pequeño (solo reaccionó una parte de mi aplicación, ya que todavía lo estoy aprendiendo) y pude lograr lo mismo de otra manera sin obtener referencias a nodos dom.
ACTUALIZAR:
Como otros han declarado en los comentarios, es mejor usar this.refs.refname
para obtener una referencia a un nodo dom. En este caso, refname es la referencia que adjuntó a su componente a través de <MyComponent ref=''refname'' />
.
Si está utilizando Backbone y React, le recomendaría uno de los siguientes,
Ambos ayudan a integrar modelos de Backbone y colecciones con vistas de React. Puede usar eventos Backbone tal como lo hace con las vistas Backbone. He incursionado en ambos y no vi mucha diferencia, excepto que uno es mixin y el otro cambia React.createClass
a React.createBackboneClass
.
bien, ya que usamos funciones para manejar un evento onchange, podemos hacerlo así:
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)} />
);
}
}
Para React 16 y React> = 15.6
Setter .value=
no funciona como queríamos porque la biblioteca React anula el valor de entrada setter pero podemos llamar a la función directamente en la input
como contexto.
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);
Para el elemento textarea debes usar el prototype
de la clase HTMLTextAreaElement
.
Nuevo ejemplo de codepen
Todos los créditos a este colaborador y su solución
Respuesta desactualizada solo para React <= 15.5
Con react-dom ^15.6.0
puede usar simulated
indicador simulated
en el objeto de evento para que el evento pase
var ev = new Event(''input'', { bubbles: true});
ev.simulated = true;
element.value = ''Something new'';
element.dispatchEvent(ev);
Hice un codepen con un ejemplo
Para entender por qué se necesita una nueva bandera, encontré este comentario muy útil:
La lógica de entrada en React ahora cambia los eventos de cambio para que no se disparen más de una vez por valor. Escucha tanto los eventos del navegador onChange / onInput como los conjuntos en el prop de valor del nodo DOM (cuando actualiza el valor a través de javascript). Esto tiene el efecto secundario de querer decir que si actualiza manualmente el valor de la entrada input.value = ''foo'', envíe un ChangeEvent con {target: input} React registrará tanto el conjunto como el evento, verá que su valor sigue siendo `''foo '', considérelo como un evento duplicado y tráguelo.
Esto funciona bien en casos normales porque un evento "real" iniciado por el navegador no desencadena conjuntos en el elemento.valor. Puedes salir de esta lógica en secreto etiquetando el evento que disparas con una bandera simulada y reaccionando siempre disparará el evento. https://github.com/jquense/react/blob/9a93af4411a8e880bbc05392ccf2b195c97502d1/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js#L128