import React, { useEffect } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; const elClassHidden = 'header--hidden'; const header = document.getElementById('header'); header.removeChild(document.getElementById('header_wrapper')); export default function Header({ children }) { let dHeight = 0; let wHeight = 0; let wScrollCurrent = 0; let wScrollBefore = 0; let wScrollDiff = 0; useEffect(() => { window.addEventListener('scroll', () => (!window.requestAnimationFrame) ? throttle(250, updateHeader) : window.requestAnimationFrame(updateHeader), false); }, []); let throttle = (delay, fn) => { var last, deferTimer; return function () { var context = this, args = arguments, now = +new Date; if (last && now < last + delay) { clearTimeout(deferTimer); deferTimer = setTimeout( function () { last = now; fn.apply(context, args); }, delay); } else { last = now; fn.apply(context, args); } }; }; let updateHeader = () => { dHeight = document.body.offsetHeight; wHeight = window.innerHeight; wScrollCurrent = window.pageYOffset; wScrollDiff = wScrollBefore - wScrollCurrent; if (wScrollCurrent <= 0) { // scrolled to the very top; element sticks to the top header.classList.remove(elClassHidden); } else if (wScrollDiff > 0 && header.classList.contains(elClassHidden)) { // scrolled up; element slides in header.classList.remove(elClassHidden); } else if (wScrollDiff < 0) { // scrolled down if (wScrollCurrent + wHeight >= dHeight && header.classList.contains(elClassHidden)) { // scrolled to the very bottom; element slides in header.classList.remove(elClassHidden); } else { // scrolled down; element slides out header.classList.add(elClassHidden); } } wScrollBefore = wScrollCurrent; }; return ReactDOM.createPortal(children, header); } Header.propTypes = { children: PropTypes.node };