ასინქრონული სტეტის მენეჯმენტი

პრობლემა

api-იდან წამოღებული ინფორმაციის მენეჯმენტი და წამოღებაც კი არის გასაკვირად ჩელეჯნჯინგი რეაქტში.

ჩვენ შეგვიძლია უბრალოდ დავწეროთ ამდგავარი რამ როცა მოგვინდება რომ წამოვიღოთ ბექიდან ინფორმაცია და ის გამოვიყენოთ

import { useEffect, useState } from 'react';
import { getOpportunities } from 'utils/apis/opportunities';

const Demo = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<any>(null);

  useEffect(() => {
    (async () => {
      try {
        setLoading(true);
        const response = await getOpportunities();
        const data = await response.json();
        setData(data);
      } catch (error: any) {
        setError(error);
      } finally {
        setLoading(false);
      }
    })();
  }, []);

  if (loading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return (
    <div>
      <h1>Opportunities</h1>
      <ul>
        {data.map((opportunity) => (
          <li key={opportunity.id}>{opportunity.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Demo;

აქ უამრავი პრობლემა, ჯერ ერთი რომ useEffect-ს ვიყენებთ ინფორმაციის წამოიღებისთვის რაც არ არის კარგი იდეა (ამაზე სხვა სექციაშI ვისაბრებთ გრძლად), ყველა სტეტის დაჰენდვლა, ლოადინგის data-ის, ერრორის ჩვენით გვიწევს ყველა ჯერზე, ინფორმაციის ახლიდან წამოღება რომ დაგვჭირდეს მაშინ რას ვიზამთ? ანუ რომ მოგვინდეს ოპპორტუნიტების ახლიდან წამოღება როცა ახალი დაემატება, useEffect-ში ჩავამატებთ დეპენდენსის რომელსაც შევცვლით, ესეც არასწორი გამოყენება useEffect-ის, ან შეგვიძლია რომ ახლიდან დავწეროთ წამოღების ლოგიკა და ეგ ეგრე შევცვალოთ, სადაც ისევ მოგვიწევს ჩვენ ლოადინგის და ერრორის ახლიდან დაჰენდვლა.

ეს დიდ აპლიკაციაებშI ძალიან მალე გაიქცევა ხელიდან და ძალიან ძნელი დასამენეჯებელი იქნება.

მენეჯმენტის გარდა მერე ქეშირება დაგვჭრირდება, retry policy, pooling, infinite scroll, პოსტ რექუესტების გაგზავნაც დაგვჭირდება, ყველა კომპონენტიდან ახლიდან რომ არ წავიდეთ ბექში ეგ დაგვჭირდება.

ეს ყველაფერი ხელით გაკეთებადია რათქმაუნდა მაგრამ საკმაოდ ბევრი საქმეა და ხელიდან იმპლიემნტაცია ამის დიდად არ ღირს.

პრობლემის მოგვარება (ვერსია 1)

უადველსი ვერსია რომ ეს მოვაგვაროთ იქნება ერთი custom hook-ს გაკეთება, სადაც არ გამოვიყენებთ useEffect-ს, რაღაცა ამდაგვარი

import { AxiosResponse } from 'axios';
import { useState } from 'react';

export const useFetch = <T extends AxiosResponse, K = T['data']>(
  handler: () => Promise<T>,
  transformData: (arg0: T) => K,
) => {
  const [data, setData] = useState<K | null>(null);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<any>(null);

  if (!loading) {
    () =>
      (async () => {
        try {
          setData(transformData(await handler()));
        } catch (error) {
          setError(error);
        } finally {
          setLoading(false);
        }
      })();
  }

  const alterData = (data: K) => {
    setData(data);
  };

  return { data, loading, error, alterData };
};

ეს საკმაოდ ადვილი ჰუკია მაგრამ ამის პრობლემა ის არის რომ ბევრი რაღაცა არ შეიძლება და მერე ყვეალფრის იმპლიმნეტაცია ხელით მოგივწევს, მაგრამ თU პატარა აპლიკაცია და ბევრი რექუესტის გაგზავნა არ დაგვჭირდება ამის გამოყნეება სრულიად ვალიდურია.

  • მთელი კოდი ჩვენი აპლიკაციის მხარეს არის და დეპენდენსები არ გვაქ

  • ყველა რექუესტის მმოთხოვნა ერთია დგილიდან ქინება რამე მოდიფიკაცია თუ დაგვჭირდება გლობალურად, მაგ: ქეშირება, საკმაოდ ადვილი ჩასამატებელი იქნება

  • არ ვიყენებთ useEffect-ს

პრობლემის მოგვარება (ვერსია 2)

ალბათ საუკეთესო გზა რომ მოვაგვაროთ ასინქრონული სტეტის მენეჯმენტი არის tanstack query, tansta

Last updated