Skip to content

Instantly share code, notes, and snippets.

@aandrewww
Last active May 21, 2020 13:07
Show Gist options
  • Select an option

  • Save aandrewww/a33d5142fd657baf717f4230ae0ece26 to your computer and use it in GitHub Desktop.

Select an option

Save aandrewww/a33d5142fd657baf717f4230ae0ece26 to your computer and use it in GitHub Desktop.

Revisions

  1. aandrewww revised this gist May 21, 2020. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions react-sticky-element.jsx
    Original file line number Diff line number Diff line change
    @@ -12,9 +12,6 @@ const styles = {
    position: 'fixed',
    zIndex: 2,
    top: 0,
    left: 0,
    right: 0,
    backgroundColor: '#f0f0ec',
    },
    };

  2. aandrewww revised this gist May 21, 2020. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion react-sticky-element.jsx
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@
    import * as R from 'ramda';
    import React, {
    useRef, useEffect, useCallback, useState,
    } from 'react';
  3. aandrewww renamed this gist May 21, 2020. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. aandrewww renamed this gist May 21, 2020. 1 changed file with 0 additions and 0 deletions.
  5. aandrewww created this gist May 21, 2020.
    69 changes: 69 additions & 0 deletions react hook - sticky element (with rxjs)
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    import * as R from 'ramda';
    import React, {
    useRef, useEffect, useCallback, useState,
    } from 'react';
    import { fromEvent, merge } from 'rxjs';
    import PropTypes from 'prop-types';

    const styles = {
    wrapper: {
    position: 'relative',
    },
    sticky: {
    position: 'fixed',
    zIndex: 2,
    top: 0,
    left: 0,
    right: 0,
    backgroundColor: '#f0f0ec',
    },
    };

    export const StickyWrapper = ({ children, top }) => {
    const [isSticky, setSticky] = useState(false);
    const ref = useRef(null);

    const handleScroll = useCallback(() => {
    // Make sure ref has current attibute and getBoundingClientRect function
    // otherwise, it could cause getBoundingClientRect undefined error.
    if (ref && ref.current && ref.current.getBoundingClientRect()) {
    // Then, we compare the distance of the ref component to the top
    // with top value we set. If less than, we set isStick true.
    const { top: elTop, height: elHeight } = ref.current.getBoundingClientRect();

    if (!ref.current.style.height) {
    ref.current.style.height = `${elHeight}px`;
    }

    setSticky(elTop <= top);
    }
    }, [top]);

    useEffect(() => {
    const elementSubscription = merge(
    fromEvent(window, 'scroll'),
    fromEvent(window, 'resize'),
    ).subscribe(handleScroll);

    return () => {
    elementSubscription.unsubscribe();
    };
    }, [handleScroll]);

    return (
    <div style={styles.wrapper} ref={ref}>
    <div style={isSticky ? styles.sticky : {}}>
    {children}
    </div>
    </div>
    );
    };

    StickyWrapper.propTypes = {
    children: PropTypes.node.isRequired,
    top: PropTypes.number,
    };

    StickyWrapper.defaultProps = {
    top: 0,
    };