Estoy desarrollando una aplicación React JS que se supone que se ejecuta en dispositivos móviles.
Aquí están los extractos del código de la aplicación:
índice.tsx:
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; ReactDOM.render( <React.StrictMode> <App/> </React.StrictMode>, document.getElementById('root') );Aplicación.tsx:
import React from 'react'; import './App.css'; import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; import {Header} from "./Components/header" import {Footer} from "./Components/footer" import {Sidebar} from "./Components/sidebar" //... const listener = () => { console.log("Main listener") }; function App() { const media = window.matchMedia('(min-width: 700px)'); media.addEventListener("change", listener); return ( <Router> <div className="App"> <Header /> <Sidebar /> <Footer /> //... </div> </Router> ); } export default App; ¡El problema es que la función del controlador de eventos de change ( listener ) se llama DOS VECES! cuando cambio el tamaño de la ventana del navegador. He leído que investigué que el motivo es la etiqueta React Strict Mode . Como dice el documento oficial , el Strict Mode hace una doble invocación de las siguientes funciones:
Constructor de componentes de clase, renderizar y métodos shouldComponentUpdate
Componente de clase método estático getDerivedStateFromProps
Cuerpos de componentes de función
Funciones de actualización de estado (el primer argumento de setState)
Funciones pasadas a useState, useMemo o useReducer
Mi pregunta es ¿POR QUÉ el evento vinculado se llama DOS VECES ya que el documento no enumera los controladores de eventos como invocados dos veces?
¿Es ese contexto LO QUE finalmente hace que el evento de change se invoque dos veces?
Este es el StrictMode de React que le llama la atención de manera proactiva sobre un error. No debe suscribirse a eventos en el nivel superior de una función de componente, porque se llama cada vez que se procesa el componente, por lo que cada vez que agrega una nueva suscripción al evento. Cuando tiene varias suscripciones a un evento (en diferentes objetos de origen de eventos), recibe varias devoluciones de llamada a su devolución de llamada de evento (una para cada suscripción).
En su lugar, suscríbase una vez en una devolución de llamada de useEffect con una matriz de dependencias vacía (y anule la suscripción de una devolución de llamada de limpieza que devuelve), detalles aquí .
function App() { // An effect only called once on mount (empty deps array) useEffect(() => { // Subscribe once const media = window.matchMedia("(min-width: 700px)"); media.addEventListener("change", listener); // Unsubscribe on unmount return () => { media.removeEventListener("change", listener); }; }, []); // ... }En un comentario has preguntado:
... ¿Pueden explicarme POR QUÉ la siguiente suscripción a eventos múltiples no es explícita?
media.addEventListener("change", listener); media.addEventListener("change", listener)
Porque en ese código, está llamando a addEventListener dos veces en la misma MediaQueryList y pasando el mismo controlador de eventos ( listener ). Si agrega el mismo oyente para el mismo evento al mismo objeto dos veces, la segunda vez se ignora (por el sistema de eventos DOM; diferentes sistemas lo manejan de manera diferente).
Pero eso no es lo que está haciendo su componente. La función de su componente se ejecuta más de una vez, y cada vez crea una nueva MediaQueryList y le agrega un controlador, como este:
const listener = () => { console.log("listener fired"); }; const YourComponent = () => { const media = window.matchMedia("(min-width: 700px)"); media.addEventListener("change", listener); }; YourComponent(); YourComponent();O para decirlo aún más claramente:
const media1 = window.matchMedia("(min-width: 700px)"); media1.addEventListener("change", listener); const media2 = window.matchMedia("(min-width: 700px)"); media2.addEventListener("change", listener); Dado que son objetos MediaQueryList diferentes, el oyente se agrega cada vez (una vez a cada objeto).
Si ejecuta ese fragmento, cambie el tamaño de su navegador para que el oyente se dispare, verá que se dispara dos veces.