RSS Amplifier

hjf's feed · Sep 13, 2019

React Progress Bars

0
Sign in to vote or save

Harry · Harry

$ cat

~/posts/react-scroll-bars.mdx

Published on

Sep 13, 2019

Progress bars make a blog look cooler. More importantly, it lets the reader know that they’re almost finished with the article, which if good, if you’re overstimulated.

They’re easy to add, I’ve added one to lumen, the template that this blog is based on.

First, add the code to make it work. You’re probably looking for this -

class Page extends React.Component {
  constructor(props) {
    super(props)
    this.state = {progress: '0%'}
    this.setScroll = this.setScroll.bind(this)
  }
  componentDidMount() {
    this.setScroll()
    window.addEventListener('scroll', this.setScroll)
  }
  componentWillUnmount() {
    window.removeEventListener('scroll', this.setScroll)
  }
  setScroll() {
    const winScroll = document.body.scrollTop || document.documentElement.scrollTop
    const height = document.documentElement.scrollHeight - document.documentElement.clientHeight
    const scrolled = (winScroll / height) * 100
    const scrollPerc = `${scrolled}%`
    this.setState({ scrollPerc })
  }
}

Here, we set an initial state - scrolled 0%. We also add an event listener to update the state on scroll. The magic happens within setScroll() — we calculate the scroll position and the height of the window. Height it calculated as scrollHeight - clientHeight so that the bar starts at 0, and when we hit the bottom of the page, the bar hits 100%.

Then, we sprinkle in a bit of JSX -

<div className="post-progress" style={{width: this.state.scrollPerc}}

And a bit of styling to boot -

.post-progress {
    position: fixed;
    height: 3px;
    top: 0;
    left: 0;
    background: $color-primary;
}

By updating state on each scroll, the component re-renders and div.post-progress gets wider (or thinner) based on the scroll, looking like a scrollbar.

The code examples are used ad verbatim in this blog - give them a go!


Update (20-Sep-2019): Migrated to Hooks

Since migrating the site to hooks, The code for this is significantly cleaner.

The component is done with a functional component, with a custom useScroll hook. It looks like this:

function useScroll() {
	const [scrollPerc, setScrollPerc] = useState(getScrollPerc())
	const setScroll = () => setScrollPerc(getScrollPerc())
	useEffect(() => {
		window.addEventListener('scroll', setScroll)
		return () => window.removeEventListener('scroll', setScroll)
	})
	return scrollPerc
}

The original getScrollPerc() from before is used. It’s used by setScroll, a higher-order function. This means that an event listener can be added and removed.

useEffect is used to set an event listener that updates the state and by returning window.removeEventListener(......), the component can cleanup on unmount.

Read the original on hjf.io

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.