Tengo un SPA con una página de gran altura, donde una sección representa una página. Código real:
const ScrollWrapper = () => { return ( <div className={styles.ScrollWrapper + ` ` + 'snap-container'}> <div className={styles['navigation-fix-wrapper']}> <ScrollNavigation/> </div> <Home/> <Projects/> <Media/> <Concerts/> <Contacts/> </div> )};A tener un componente de navegación en la parte superior. Es un montón de anclas con elementos de lista dentro, cada ancla se vincula a secciones como con efecto de desplazamiento, sin cambios de página. Al hacer clic, el estilo de un enlace en el que se hizo clic cambia a activo.
Objetivo: implementar IntersectionObserver en todas mis secciones (desde Inicio hasta Contactos) y, según el componente que esté en la vista, se cambiará el enlace activo en el componente ScrollNavigation (si me desplazo desde Inicio a Conciertos, el enlace Conciertos estará activo)
No tengo absolutamente ninguna idea de cómo puedo hacerlo, pero estoy bastante seguro de que hay algunas formas.
Pienso en algo como (pseudocódigo):
const [activeLink, setActiveLink] = useState('home') //some code here if (IntersectionObserver.state === 'home' { setActiveLink('home') } else if (IntersectionObserver.state === 'concerts' { setActiveLink('concerts') } //some code here return ( <div className={styles.ScrollWrapper + ` ` + 'snap-container'}> <ScrollNavigation active={activeLink} /> //some code here </div> )ACTUALIZAR:
Se agregó este código a ScrollWrapper, como sugirió kritiz. IntersectionObserver activa console.log solo si el componente principal está en la condición if, pero no los secundarios. ¿Qué estoy haciendo mal?
useEffect(() => { var observer = new IntersectionObserver(onIntersection, { root: null, // default is the viewport threshold: .5 // percentage of taregt's visible area. Triggers "onIntersection" }) // callback is called on intersection change function onIntersection(entries, opts){ entries.forEach(entry => { if (entry.target.id === 'projects') { console.log('projects') } } ) } observer.observe( document.querySelector('.snap-container') ) }, [])Se cambió el objetivo a currentTarget, se produce un error:
Cannot read properties of undefined (reading id)Como sugirió kritiz, usé un detector de eventos de desplazamiento en la ventana y realmente funcionó. Todavía suena como fugas de memoria, y continuaré intentando implementar IntersectionObserver, pero funciona como lo necesitaba.
Código:
useEffect(() => { window.addEventListener('scroll', function() { const observable = { home: document.querySelector('.home'), projects: document.querySelector('.projects'), media: document.querySelector('.media') } const pos = { home: observable.home.getBoundingClientRect(), projects: observable.projects.getBoundingClientRect(), media: observable.media.getBoundingClientRect() } if (pos.home.top < window.innerHeight && pos.home.bottom >= 0) { setActiveLink('home') } else if (pos.projects.top < window.innerHeight && pos.projects.bottom >= 0) { setActiveLink('projects') } else if (pos.media.top < window.innerHeight && pos.media.bottom >= 0) { setActiveLink('media') } }) return () => { } }, [])ACTUALIZAR:
El segundo enfoque es usar la biblioteca react-scroll , que funciona de maravilla y hace todo lo que necesito.