React: Как оптимизировать пользовательский хук, который обменивается данными? - PullRequest
3 голосов
/ 10 октября 2019

У меня есть Custom Hook, аналогично приведенному ниже:

import { useEffect, useState } from 'react';

import axios from 'axios';

const myCustomHook = () => {
  const [countries, setCountries] = useState([]);
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {
      (async () =>
        await axios
          .get("MY_API/countries")
          .then(response => setCountries(response.data))
          .finally(() => setLoading(false)))();
  }, []);

  return countries;
};

export default myCustomHook;

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

Есть ли хороший шаблон для вызова запроса axios только один раз вместо трех?

РЕДАКТИРОВАТЬ - окончательный код после решения

import { useEffect, useState } from 'react';

import axios from 'axios';

let fakeCache = {
    alreadyCalled: false,
    countries: []
};

const myCustomHook = (forceUpdate = false) => {
  const [isLoading, setLoading] = useState(true);

  if (!fakeCache.alreadyCalled || forceUpdate) {
      fakeCache.alreadyCalled = true;

      (async () =>
        await axios
          .get("MY_API/countries")
          .then(response => setCountries(response.data))
          .finally(() => setLoading(false)))();
  }

  return countries;
};

export default myCustomHook;

Ответы [ 2 ]

1 голос
/ 10 октября 2019

Одним из решений этой проблемы было бы введение пользовательского «слоя кэширования» (между вашей ловушкой и запросом axios), который:

  1. кэширует coutries данные, возвращаемые из первого успешного запроса, и,
  2. возвращает те же кэшированные данные при последующих запросах

Существует несколько способов, которыми это может быть реализовано - одна из возможностей - определить функцию getCountries(), которая реализует эту логику кэширования. в отдельном модуле, а затем вызвать эту функцию из вашего хука:

country.js

import axios from 'axios';

// Module scoped variable that holds caches data
let cachedData = undefined;

// Example function wraps network request with caching layer
export const getCountries = async() => {

  // We expect the data for countries to be an array. If cachedData
  // is not an array, attempt to populate the cache with data
  if (!Array.isArray(cachedData)) {  
    const response = await axios.get("MY_API/countries");

    // Populate the cache with data returned from request
    cachedData = response.data;
  }

  return cachedData;
}

myCustomHook.js

import { useEffect, useState } from 'react';
import { getCountries } from "/countries";

const myCustomHook = () => {
  const [countries, setCountries] = useState([]);
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {

    (async() => {
      try {       
        setLoading(true);

        // Update hooks state with countries data (cached or fresh)
        setCountries(await getCountries());

      } finally {
        setLoading(false)
      }
    }, []);
  });
}
export default myCustomHook;
0 голосов
/ 10 октября 2019

Каждый экземпляр компонента работает независимо друг от друга.

Несмотря на заполнение состояния 1-го экземпляра countries, 2-й экземпляр не знает об этом и все еще пуст.

Вместо этого вы могли бы потреблять countries в качестве реквизита, а если пусто, вызывать эффект, в противном случае просто вернуть countries из реквизита.

...