Necesito configurar un campo de estado que obtengo de un evento, pero no se configura cuando le paso una función. El componente y el método tienen el siguiente aspecto:
constructor(props: SomeProps, context: any) { super(props, context); this.state = { isFiltering: props.isFiltering, anchor: "", }; } private toggleFilter = (event: any) => { event.persist() this.setState(prevState => ({ isFiltering: !prevState.isFiltering, anchor: event.currentTarget // does not work, it's null })); }
Si event.persist()
, obtengo el siguiente error:
Este evento sintético se reutiliza por motivos de rendimiento. Si ve esto, está accediendo al método
currentTarget
en un evento sintético liberado/anulado. Esta es una función no operativa. Si debe conservar el evento sintético original, utilice event.persist(). Consulte https://facebook.github.io/react/docs/events.html#event-pooling para obtener más información.
Por alguna razón, el siguiente código funciona:
private toggleFilter = (event: any) => { this.setState({anchor:event.currentTarget}) // works fine this.setState(prevState => ({ isFiltering: !prevState.isFiltering, })); }
¿Por qué funciona lo anterior pero no cuando uso this.setState(prevState=> ...)
?
Ese es el comportamiento esperado , porque event.persist()
no implica que currentTarget
no se anule, de hecho, debería serlo, es compatible con la implementación nativa del navegador.
Esto significa que si desea acceder a currentTarget de forma asíncrona, debe almacenarlo en caché en una variable como lo hizo en su respuesta.
Para citar a uno de los desarrolladores principales de React: Sophie Alpert .
currentTarget cambia a medida que el evento surge: si tuviera un controlador de eventos en el elemento que recibe el evento y otros en sus ancestros, verían diferentes valores para currentTarget. La anulación de IIRC es consistente con lo que sucede en los eventos nativos; si no, házmelo saber y reconsideraremos nuestro comportamiento aquí.
Consulte la fuente de la discusión en el repositorio oficial de React y el siguiente fragmento proporcionado por Sophie que he tocado un poco.
var savedEvent; var savedTarget; divb.addEventListener('click', function(e) { savedEvent = e; savedTarget = e.currentTarget; setTimeout(function() { console.log('b: currentTarget is now ' + e.currentTarget); }, 0); }, false); diva.addEventListener('click', function(e) { console.log('same event object? ' + (e === savedEvent)); console.log('same target? ' + (savedTarget === e.currentTarget)); setTimeout(function() { console.log('a: currentTarget is now ' + e.currentTarget); }, 0); }, false);
div { padding: 50px; background: rgba(0,0,0,0.5); color: white; }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> </head> <body> <div id="diva"><div id="divb"> Click me and see output! </div></div> </body> </html>
Con el comentario de @thirtydot obtuve una solución funcional.
Creo que es porque setState es "asincrónico", por lo que cuando se ejecuta la función que pasa a setState (y se accede al evento), el evento ya no existe. En la segunda versión, se accede al evento inmediatamente y su objetivo actual se pasa a setState
Así que event.currentTarget
en una variable y lo usé como se explica en ReactJs Event Pooling
Se parece a esto y funciona
private toggleFilter = (event: any) => { let target = event.currentTarget; this.setState((prevState) => ({ isFiltering: !prevState.isFiltering, anchor: target })); }
Sin embargo, esto no explica por qué event.persist()
no funciona. Aceptaré la respuesta que lo explica.
Para resolver este problema, antes de llamar a handleSubmit de formulario, llame a event.persist() y luego en la definición de handleSubmit(), escriba su lógica. Por ejemplo
<form id="add_exp_form" onSubmit={(event) => {event.persist();this.handleSubmit(event)}}> handleSubmit(event){ // use event.currentTarget - It will be visible here }