React:如何优化共享数据的自定义钩子?

时间:2019-10-09 23:02:56

标签: javascript reactjs request axios

与下面类似,我也有一个自定义挂钩:

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 个答案:

答案 0 :(得分:1)

一种解决方案是引入一个自定义的“缓存层”(在您的钩子和axios请求之间):

  1. 缓存第一个成功请求返回的coutries数据,并且
  2. 在后续请求中返回相同的缓存数据

有多种方法可以实现-一种可能性是定义一个getCountries()函数,该函数在单独的模块中实现该缓存逻辑,然后从钩子中调用该函数:

countries.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;

答案 1 :(得分:0)

该组件的每个实例彼此独立运行。

即使第一个实例状态填充了countries,第二个实例也不知道,并且仍然为空。

您可以改为使用countries作为道具,如果为空则调用效果,否则只需从道具返回countries