actualmente estoy creando una barra de navegación que solo se muestra cuando se desplaza hacia arriba, para evitar que useEffect se ejecute cada vez que cambia el estado visible, tuve que usar tanto una referencia como un estado sincronizado para hacer una comparación en useEffect, usando ref y un estado para realizar un seguimiento de un mismo valor parece extremadamente sospechoso, ¿hay otra forma de hacerlo? ¿uno que no implique activar useEffect para que no cree los controladores de eventos cada vez que cambia el estado?
import React, { useState, useRef, useEffect } from 'react'; import Link from 'next/link'; const NavbarLink = ({ name, href }: { name: string, href: string }) => { return ( <Link href={href}> <a>{ name }</a> </Link> ); } const Navbar = () => { const scrollYRef = useRef(0); const visibleRef = useRef(true); const [visible, setVisible] = useState(true); useEffect(() => { const onScroll = (event: Event) => { event.preventDefault(); if ((window.scrollY < scrollYRef.current) != visibleRef.current) { visibleRef.current = !visibleRef.current; setVisible(x => !x); } scrollYRef.current = window.scrollY; } window.addEventListener('scroll', onScroll); return () => { window.removeEventListener('scroll', onScroll); } }, []); return ( <div className={`${!visible && '-translate-y-full'} fixed flex w-full h-32 font-bold text-white transition-all`}> <NavbarLink name="home" href='/'/> </div> ); }Puede usar el patrón "última referencia" (aquí a través del gancho useLatest react-use ), que encuadra el valor más reciente de un átomo de estado en cada momento de actualización del componente, por lo que no necesita administrarlo manualmente, y no No lo necesito como una dependencia para el gancho. (También tomaría useEvent de react-use si terminas usándolo).
import React, { useState, useRef, useEffect } from "react"; import Link from "next/link"; // via https://github.com/streamich/react-use/blob/master/src/useLatest.ts const useLatest = (value) => { const ref = useRef(value); ref.current = value; return ref; }; const NavbarLink = ({ name, href }: { name: string; href: string }) => { return ( <Link href={href}> <a>{name}</a> </Link> ); }; function useVisibleOnScrollUp(initial = true) { const scrollYRef = useRef(window.scrollY); const [visible, setVisible] = useState(initial); const latestVisibleRef = useLatest(visible); useEffect(() => { const onScroll = (event: Event) => { event.preventDefault(); const currentVisible = latestVisibleRef.current; if (window.scrollY < scrollYRef.current != currentVisible) { setVisible((x) => !x); } scrollYRef.current = window.scrollY; }; window.addEventListener("scroll", onScroll); return () => { window.removeEventListener("scroll", onScroll); }; }, []); return visible; } const Navbar = () => { const visible = useVisibleOnScrollUp(true); return ( <div className={`${ !visible && "-translate-y-full" } fixed flex w-full h-32 font-bold text-white transition-all`} > <NavbarLink name="home" href="/" /> </div> ); };