JavaRush /Курсы /Модуль 3: React /Создание хуков для работы с API и AsyncStorage

Создание хуков для работы с API и AsyncStorage

Модуль 3: React
24 уровень , 8 лекция
Открыта

Создание хука для работы с API

Кастомные хуки позволяют нам повторно использовать сложную бизнес-логику, такую как выполнение API-запросов, управление состоянием загрузки или сохранением данных в AsyncStorage. Они помогают держать код компонентов чистым и более читаемым, что особенно важно в крупном приложении с множеством состояний и взаимодействий.

Давайте представим, что вы разрабатываете приложение для заметок. Вам нужно, чтобы данные о заметках загружались с сервера, кэшировались в локальном хранилище, а при отсутствии интернета подгружались из AsyncStorage. Как управлять всем этим хаосом?

Начнем с реализации хука, который будет управлять процессом API-запросов. Назовем его useFetch.

Реализация useFetch

import { useState, useEffect } from "react";
import axios from "axios";

interface FetchState<T> {
  data: T | null; // Загруженные данные
  isLoading: boolean; // Состояние загрузки
  error: string | null; // Ошибка, если произошла
}

export const useFetch = <T>(url: string) => {
  const [state, setState] = useState<FetchState<T>>({
    data: null,
    isLoading: true,
    error: null,
  });

  useEffect(() => {
    const fetchData = async () => {
      try {
        setState({ data: null, isLoading: true, error: null });
        const response = await axios.get<T>(url); // Отправка GET-запроса
        setState({ data: response.data, isLoading: false, error: null });
      } catch (error: any) {
        setState({ data: null, isLoading: false, error: error.message });
      }
    };

    fetchData();
  }, [url]);

  return state; // Возвращаем состояние
};

Использование useFetch

Теперь мы можем использовать этот хук для загрузки данных в наших компонентах:

import React from "react";
import { View, Text, ActivityIndicator, FlatList } from "react-native";
import { useFetch } from "./hooks/useFetch";

interface Note {
  id: number;
  title: string;
  content: string;
}

const NotesScreen: React.FC = () => {
  const { data, isLoading, error } = useFetch<Note[]>("https://api.example.com/notes");

  if (isLoading) return <ActivityIndicator size="large" color="#0000ff" />;
  if (error) return <Text>Error: {error}</Text>;

  return (
    <FlatList
    data={data}
    keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => (
        <View>
          <Text>{item.title}</Text>
          <Text>{item.content}</Text>
        </View>
      )}
    />
  );
};

export default NotesScreen;

Теперь загрузка данных из API максимально проста — просто вызываем наш хук!

Создание хука для работы с AsyncStorage

Дальше мы реализуем хук для хранения данных в AsyncStorage. Этот хук будет включать операции чтения и записи данных.

Реализация useAsyncStorage

import AsyncStorage from "@react-native-async-storage/async-storage";
import { useState, useEffect } from "react";

export const useAsyncStorage = <T>(key: string, initialValue: T) => {
  const [value, setValue] = useState<T>(initialValue);

  // Сохранение в AsyncStorage
  const saveToStorage = async (newValue: T) => {
    try {
      const jsonValue = JSON.stringify(newValue);
      await AsyncStorage.setItem(key, jsonValue);
      setValue(newValue);
    } catch (error) {
      console.error("Failed to save to AsyncStorage:", error);
    }
  };

  // Загрузка из AsyncStorage
  useEffect(() => {
    const loadFromStorage = async () => {
      try {
        const jsonValue = await AsyncStorage.getItem(key);
        if (jsonValue !== null) {
          setValue(JSON.parse(jsonValue));
        }
      } catch (error) {
        console.error("Failed to load from AsyncStorage:", error);
      }
    };

    loadFromStorage();
  }, [key]);

  return [value, saveToStorage] as const;
};

Использование useAsyncStorage

Теперь мы можем хранить данные локально с помощью хука:

 import React from "react";
import { View, Button, Text } from "react-native";
import { useAsyncStorage } from "./hooks/useAsyncStorage";

const Counter: React.FC = () => {
  const [count, setCount] = useAsyncStorage<number>("counter", 0);

  return (
    <View>
      <Text>Count: {count}</Text>
      <Button title="Increment" onPress={() => setCount(count + 1)} />
    </View>
  );
};

export default Counter;

Каждое нажатие на кнопку обновляет значение в AsyncStorage и сразу же отображает новое значение на экране.

Комбинирование хуков для работы с API и AsyncStorage

Теперь давайте объединим оба подхода. Мы создадим хук, который будет одновременно работать с API и сохранять данные в AsyncStorage для кэширования. Назовем его useCachedFetch.

Реализация useCachedFetch

import { useFetch } from "./useFetch";
import { useAsyncStorage } from "./useAsyncStorage";
import { useEffect } from "react";

export const useCachedFetch = <T>(url: string, cacheKey: string, initialValue: T) => {
  const { data, isLoading, error } = useFetch<T>(url);
  const [cachedData, setCachedData] = useAsyncStorage<T>(cacheKey, initialValue);

  useEffect(() => {
    if (data) {
      setCachedData(data); // Кэшируем данные, если они загружены
    }
  }, [data, setCachedData]);

  return { data: cachedData || data, isLoading, error };
};

Использование useCachedFetch

import React from "react";
import { View, Text, ActivityIndicator, FlatList } from "react-native";
import { useCachedFetch } from "./hooks/useCachedFetch";

interface Note {
  id: number;
  title: string;
  content: string;
}

const NotesScreen: React.FC = () => {
  const { data, isLoading, error } = useCachedFetch<Note[]>(
    "https://api.example.com/notes",
    "cached_notes",
    []
  );

  if (isLoading) return <ActivityIndicator size="large" color="#0000ff" />;
  if (error) return <Text>Error: {error}</Text>;

  return (
    <FlatList
    data={data}
    keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => (
        <View>
          <Text>{item.title}</Text>
          <Text>{item.content}</Text>
        </View>
      )}
    />
  );
};

export default NotesScreen;

Теперь даже если у пользователя пропадет интернет, приложение будет загружать данные из кэша AsyncStorage, обеспечивая стабильную работу.

Типичные ошибки и советы

При работе с API и AsyncStorage стоит помнить о следующих нюансах:

  1. Никогда не храните конфиденциальные данные, такие как пароли, в AsyncStorage, так как это небезопасно.
  2. Обрабатывайте все ошибки при работе с сетью try-catch, так как соединение может быть нестабильным.
  3. Следите за актуальностью данных в кэше — обновляйте их при изменении на сервере.

Сочетание API и локального хранилища — это ключевая особенность современных мобильных приложений, которая помогает создавать быстрые и отзывчивые интерфейсы. Теперь с кастомными хуками ваш код будет не только работать, но и прекрасно выглядеть!

2
Задача
Модуль 3: React, 24 уровень, 8 лекция
Недоступна
Реализация простого хука для AsyncStorage
Реализация простого хука для AsyncStorage
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ