Skip to content

A small project that implements the functionality of content loading by scroll and validation of the response from the slicer

Notifications You must be signed in to change notification settings

DmitryLasuta/dynamic-scroll

Repository files navigation

Infinity Scroll with response validation

A small project that implements the functionality of content loading by scroll and validation of the response from the slicer

Technologies Used 🛠️

React TypeScript TailwindCSS React Query Zod

Key features 🔑

  • Infinite scrolling using the custom useIntersection hook.
  • Data validation using the Zod library.
  • Error handling via ErrorBoundary component.
  • Universal API class for working with requests.

Description 👾

PostsList is the main React component of the project, implementing infinite scrolling to display a list of posts using the Intersection Observer API. The component includes a clever architecture for data processing, validation of the response from the API, and robust error handling.

Core functionality 🧠

API class

The project uses an abstract API class for unified API handling.

Features

  • Base URL: Set once when the child class is initialized.

  • Response validation: Each response is validated through a Zod schema to ensure that the data is correct.

  • Method fetcher: Universal method for executing HTTP requests.

  • Error Management: A detailed error message is generated if the data structure is incorrect.

API response validation

  • Each data upload is rigorously validated through Zod.

  • PostSchema and PostsSchema schemas are used to ensure that the response structure is as expected.

  • If the data is not valid, the request is terminated with an error, which helps avoid incorrect data display.

Infinite scrolling with useIntersection

  • The useIntersection hook uses IntersectionObserver to track the intersection of an item (ref to “cursor” at the end of the list) with the viewing area.

  • Once the user reaches the end of the list, the fetchNextPagePostList colback is triggered.

  • Implemented automatic unsubscribe via observer.disconnect() when the tracked item is unmounted or changed.

Data loading

  • When the component is first rendered, the first page of posts is loaded.

  • Further loading occurs automatically when the end of the list is reached.

Loading States

  • If data is being loaded, the user sees the Loading.... message

  • Once the data is successfully loaded, it is rendered on the page.

Working with API

  • The useGetPostList hook controls request states (load, successful completion, errors).

  • Data is loaded page by page via the fetchNextPage method.

Error handling

  • The project uses ErrorBoundary component for safe operation of the application. It intercepts errors and displays a friendly message to the user.

Dynamic rendering

  • The list of posts is represented as cards (PostCard), each of which displays data from the API.

How it works? 🚀

API Class

  • API class basic structure:

    export abstract class API {
    protected baseUrl: string;
    
    constructor(baseUrl: string) {
      this.baseUrl = baseUrl;
    }
    protected async fetcher<T extends z.ZodTypeAny>({
      endpoint,
      options,
      schema,
      schemaName,
    }: FetcherParams<T>): Promise<z.infer<T>> {
      const response = await fetch(`${this.baseUrl}${endpoint}`, options);
    
      if (!response.ok) {
        throw new Error(`Request failed with status ${response.status}`);
      }
    
      const data = await response.json();
      const validationResult = schema.safeParse(data);
    
      if (!validationResult.success) {
        console.error(`Validation error in ${schemaName}:`, validationResult.error);
        throw new Error(`Invalid response for ${schemaName}`);
      }
    
      return validationResult.data;
      }
    }

Advantages

  • Unification of query logic.

  • Centralized error handling and validation.

  • Easy extensibility for creating new API classes.

Data validation via Zod

  • All data from the API is validated using schemas:

    • PostSchema: ensures that the post object contains userId, id, title and body fields with valid types.

    • PostsSchema: validates an array of PostSchema objects.

  • This reduces the chance of errors due to incorrect data.

useIntersection

  • The useIntersection structure:

    const useIntersection = (onIntersect: () => void) => {
      const unsubscribe = useRef(() => {});
      return useCallback(
        (element: HTMLDivElement | null) => {
          const observer = new IntersectionObserver(entries => {
            entries.forEach(intersection => {
              if (intersection.isIntersecting) {
                onIntersect();
              }
            });
          });
    
          if (element) {
            observer.observe(element);
            unsubscribe.current = () => observer.disconnect();
          } else {
            unsubscribe.current();
          }
        },
        []
      );
    };
  • The useIntersection hook uses IntersectionObserver to track the intersection of an item (ref to “cursor” at the end of the list) with the viewport.

  • Automatically unsubscribe via observer.disconnect() when the tracked item is unmounted or changed.

  • Universal interface for use in all lazy loading scenarios.

About

A small project that implements the functionality of content loading by scroll and validation of the response from the slicer

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published