Infinite scroll

react #ui
function PaginatedList() {
  const [page, setPage] = React.useState(1)
  const scrollEndRef = React.useRef(null)

  const [loading, setLoading] = React.useState(true)
  const [products, setProducts] = React.useState([])
  const [error, setError] = React.useState(null)

  const fetchData = async (page) => {
    try {
      setLoading(true)
      const res = await fetch(
        `https://dummyjson.com/products/?limit=40&skip=${(page - 1) * 40}`,
      )
      const data = await res.json()
      if (res.ok) {
        setProducts((prevItems) => [...prevItems, ...data.products])
      }
      setLoading(false)
    } catch (error) {
      setLoading(false)
      if (error instanceof Error) {
        setError(error)
      }
    }
  }

  const handleIntersection = (entries) => {
    if (entries.some((entry) => entry.isIntersecting)) {
      fetchData(page + 1)
    }
  }

  React.useEffect(() => {
    const observer = new IntersectionObserver(handleIntersection)

    if (scrollEndRef.current) {
      observer.observe(scrollEndRef.current)
    }

    return () => observer.disconnect()
  }, [])

  React.useEffect(() => {
    fetchData(page)
  }, [page])

  console.log(products)

  return (
    <div>
      <style>{`
				.container {
					font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
					max-width: 400px;
					max-height: 500px;
					overflow-y: auto;
					margin: 40px auto;
					padding: 0 20px;
				}

				.list {
					list-style: none;
					padding: 0;
					margin: 0 0 16px;
				}

				.list li {
					padding: 8px 0;
					border-bottom: 1px solid #e5e7eb;
				}

				.list li:first-child {
					border-top: 1px solid #e5e7eb;
				}
			`}</style>

      <div className="container">
        {loading && <div>Loading...</div>}
        {error && <div>Error: {error.message}</div>}

        <ul className="list">
          {products.map((item) => (
            <li key={item.id}>{item.title}</li>
          ))}
        </ul>

        <div ref={scrollEndRef} />
      </div>
    </div>
  )
}

export default function Demo() {
  return <PaginatedList />
}