Skip to main content

Press to Load More

The components.Footer property can be used to place a "load more" button that appends more items to the list.

Scroll to the bottom of the list and press the button to load 100 more items. The setTimeout simulates a network request; in the real world, you can fetch data from a service.

Live Editor
function App() {
  const [users, setUsers] = useState(() => [])
  const [loading, setLoading] = useState(false)

  const loadMore = useCallback(() => {
    setLoading(true)
    return setTimeout(() => {
      setUsers((users) => [...users, ...generateUsers(100, users.length)])
      setLoading(() => false)
    }, 500)
  }, [setUsers, setLoading])

  useEffect(() => {
    const timeout = loadMore()
    return () => clearTimeout(timeout)
  }, [])

  return (
    <Virtuoso
      style={{ height: 300 }}
      data={users}
      context={{ loading, loadMore }}
      increaseViewportBy={200}
      itemContent={(index, user) => {
        return <div>{user.name}</div>
      }}
      components={{ Footer }}
    />
  )
}

const Footer = ({ context: { loadMore, loading } }) => {
  return (
    <div
      style={{
        padding: '2rem',
        display: 'flex',
        justifyContent: 'center',
      }}
    >
      <button disabled={loading} onClick={loadMore}>
        {loading ? 'Loading...' : 'Press to load more'}
      </button>
    </div>
  )
}

function generateUsers(count, start) {
  return Array.from({ length: count }, (_, i) => ({
    name: `User ${start + i}`,
  }))
}


render(<App />)
Result
Loading...