El valor de estado showMenu no se actualiza dentro del gancho useEffect.

Al realizar la prueba, cuando se hace clic por primera vez en el botón y se toca la pantalla para moverse, showMenu se consuela correctamente a true. Cuando se hace clic en el botón por segunda vez (y tercero, adelante, etc.) y se toca la pantalla para moverse, showMenu continúa consolando como true cuando debería alternar a false.

const [showMenu, setShowMenu] = useState(false)

useEffect(_ => {
    const listener = e => {
        e.preventDefault()
        console.log(showMenu, ' useEffect - touchmove')
    }

    showMenu
        ? document.body.addEventListener('touchmove', listener, {passive: false})
        : document.body.removeEventListener('touchmove', listener)
}, [showMenu])

return (
    <button onclick={_ => {
        console.log(!showMenu, ' button click')
        setShowMenu(!showMenu)
    }} />
)

Resultado de la consola

enter image description here

0
Ryan Prentiss 8 feb. 2020 a las 00:54

2 respuestas

La mejor respuesta

Creo que el evento del cuerpo no se elimina correctamente, porque el oyente se cambia cada vez useEffect.

Por lo tanto, puede devolver una función en useEffect para borrar la useEffect anterior.

useEffect(() => {
    if (showMenu) {
        const listener = e => {
            e.preventDefault();
            console.log(showMenu, ' useEffect - touchmove');
        };

        document.body.addEventListener('touchmove', listener, { passive: false });

        return () => {
            document.body.removeEventListener('touchmove', listener);
        }
    }
}, [showMenu]);

También puede leer cleaning-up-an- efecto para obtener más información

1
Puckwang 7 feb. 2020 a las 22:48

No sé cuál es tu intención, pero lo que estás haciendo con useEffect probablemente no sea lo que esperas. Cuando showMenu es false, está eliminando una función listener que no se ha vinculado porque los objetos se comparan por referencia en JS y listener se redefine cada vez {{ X5}} cambios.

La forma típica de desvincular un oyente cuando useEffect cambia es devolver una función que maneja la limpieza de su devolución de llamada useEffect. Al igual que:

useEffect(() => {
  const listener = e => {
    e.preventDefault()
    console.log(showMenu, ' useEffect - touchmove')
  }

  document.body.addEventListener('touchmove', listener, { passive: false })

  return () = {
    document.body.removeEventListener('touchmove', listener, { passive: false })
  }
}, [showMenu])
1
coreyward 7 feb. 2020 a las 22:47