Many people have written about the functionality of returning to the top in native JS, but how to implement it after getting started with react project. Recently, I had this requirement in the process of doing the project, because the project’s technology stack is based on ANTD-mobile + Ahooks, there is no component to return to the top function (we know Antd has it, so when will AM follow it), without further ado, here is a simple implementation of a return to the top function.

Component packaging

Since going back to the top is used on many pages, it is best to separate it into a widget for reuse. Let’s simply encapsulate it as follows:

import styles from './style.module.scss'
import backToTop from '.. /imgs/backToTop.svg'
interface Props {
  visible: boolean
  back: () = > void
}

export default function BackToTop(props: Props) {
  return (
    <div
      className={styles.backToTop}
      onClick={()= > {
        props.back()
      }}
      style={
        props.visible ? { visibility: 'visible' } : { visibility: 'hidden' }
      }>
      <div className={styles.back}>
      <img src={backToTop} alt="" />
      <span>Return to the top</span>
      </div>
    </div>)}Copy the code

Write a simple style:

.backToTop {
  transition: all ease-in-out .05s;
  height: 20px;
  position: fixed;
  bottom: 100px;
  scroll-behavior: smooth;
  right: 20px;
}

.back {
  font-size: 12px;
  color: #007AFA;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
}
Copy the code

The component receives two arguments, visible control component shows hide, and back is the callback function passed in to scroll to the top. Now let’s actually use this component in the page. For many people, the first thing to think about is to monitor the scroll event and determine the distance of the scrollTop to control the display and hiding of the component. This time, we use the open source library Ahooks to achieve better experience. Ahooks is an open source Library of React Hooks tools by the Ant Umi team. Ahooks are packaged based on React Hooks and provide a very useful set of Hooks that make development much easier and more efficient.

Code implementation

Let’s start by importing the React-related hooks and the components we just wrapped

import React, { useEffect, useRef, useState } from 'react'
import BackToTop from '.. /components/BackToTop'
import styles from '.. /styles/Demo.module.scss'
import { useScroll } from 'ahooks'
export default function Demo() {
  // Control back to the state displayed by the top component
  const [backVisible, setBackVisible] = useState(false)
  // ref is bound to the scroll region Dom element we want to listen on
  const backRef = useRef<HTMLDivElement>(null)
  // 
  const scroll = useScroll(backRef)
  useEffect(() = > {
    if (scroll.top > 400) {
      setBackVisible(true)}else {
      setBackVisible(false)
    }
  }, [scroll.top])
  return (
    <div className={styles.list} ref={backRef}>
      <ul>
       <li>1</li>
       <li>2</li>
       <li>3</li>
       <li>4</li>
       <li>5</li>
       <li>6</li>
       <li>7</li>
       <li>8</li>
       <li>9</li>
       <li>10</li>
     </ul>
     <BackToTop
        visible={backVisible}
        back={()= >{ backRef.current? .scrollTo({ behavior: 'smooth', top: 0, left: 0 }) }} /></div>
  )
Copy the code

The throttle

A basic back to the top function is implemented, but the above code has an unreasonable place, as long as the page scroll slightly, will trigger the page scroll events frequently triggered, which causes performance problems, so we implement a throttling function:

export default function throttle(func: Function, delay: number) {
  let timer: NodeJS.Timeout | null
  return function () {
    if(! timer) { timer =setTimeout(function (this: typeof func) {
        timer = null
        func.apply(this.arguments)
      }, delay)
    }
  }
}
Copy the code

The final code looks like this:

useEffect(() = > {
    const func = throttle(() = > {
      if (scroll.top > 1000) {
        setBackVisible(true)}else {
        setBackVisible(false)}},500)
    func()
  }, [scroll.top])
Copy the code