如何使用其他文件中导出的常量中的变量?

问题描述

我将这个导出的 const 保存在一个文件 useLocation.tsx 中,我可以在其中获取用户的位置并检索用户的县、州/省和国家/地区。我还在另一个文件 const 中导出了 useCountryData.tsx,我在其中从 API 获取 COVID 病例和死亡人数。 useLocation.tsx 中有一个名为 countryNameshort 的变量。如何在 useCountryData.tsx 中使用此变量?

useLocation.tsx

export const useLocation = () => {  
  
    var [stateName,setstateName] = useState(String);
    var [countyName,setCountyName] = useState(String);
    var [countryName,setCountryName] = useState(String);
    var [stateNameshort,setstateNameshort] = useState(String);
    var [countryNameshort,setCountryNameshort] = useState(String);
  
  
  
    const [latitude,setlatitude] = useState(Number);
    const [longitude,setlongitude] = useState(Number);
  
    const [location,setLocation] = useState(Object);
    const [errorMsg,setErrorMsg] = useState(String);
      
    useEffect(() => {
          (async () => {
            if (Platform.OS === "android" && !Constants.isDevice) {
              setErrorMsg(
                "Oops,this will not work on Snack in an Android emulator. Try it on your device!"
              );
              return;
            }
            let { status } = await Location.requestPermissionsAsync();
            if (status !== "granted") {
              setErrorMsg("Permission to access location was denied");
              return;
            }
      
            let location = await Location.getCurrentPositionAsync({});
            setLocation(location);
      
            const latitude = location.coords.latitude;
            setlatitude(latitude);
            const longitude = location.coords.longitude;
            setlongitude(longitude);
          })();
        },[]);
      
        let text = "Waiting..";
        if (errorMsg) {
          text = errorMsg;
        } else if (location) {
          text = JSON.stringify(location);
        }
      
    fetch(
          "https://maps.googleapis.com/maps/api/geocode/json?address=" +
            latitude +
            "," +
            longitude +
            "&key=" +
            apiKey
        )
          .then((response) => response.json())
          .then((responseJson) => {
            const resstate = responseJson.results[0].address_components.filter(
              (x: any) =>
                x.types.filter((t: Object) => t == "administrative_area_level_1")
                  .length > 0
            )[0].long_name;
            setstateName(resstate);
            const resCounty = responseJson.results[0].address_components.filter(
              (x: any) =>
                x.types.filter((t: Object) => t == "administrative_area_level_2")
                  .length > 0
            )[0].long_name;
            setCountyName(resCounty);
            const resCountry = responseJson.results[0].address_components.filter(
              (x: any) => x.types.filter((t: Object) => t == "country").length > 0
            )[0].long_name;
            setCountryName(resCountry);
            const resstateShort = responseJson.results[0].address_components.filter(
              (x: any) =>
                x.types.filter((t: Object) => t == "administrative_area_level_1")
                  .length > 0
            )[0].short_name;
            setstateNameshort(resstateShort);
            const resCountryShort = responseJson.results[0].address_components.filter(
              (x: any) => x.types.filter((t: Object) => t == "country").length > 0
            )[0].short_name;
            setCountryNameshort(resCountryShort);
            if (countryNameshort === "US") {
              countryNameshort = "US" + "A";
            }
          })
          .catch((err) => {
            console.log(err);
          });

        return { countryName,countyName,stateName,stateNameshort,countryNameshort };
      };

useCountryData.tsx

import { useLocation } from './useLocation';

export const useCountryData = () => {
  const [earliest2,setEarliest2] = useState([]);
  const [countryDeaths,setcountryDeaths] = useState(Number);
  const [countryCases,setcountryCases] = useState(Number);

  useEffect(() => {
    axios
      .get("https://coronavirus-19-api.herokuapp.com/countries")
      .then((response) => {
        setEarliest2(response.data);

        const countryArray = response.data.filter(
          (item) => item.country === props.countryNameshort //???
        );

        const resCountryDeaths = countryArray[0].deaths;
        setcountryDeaths(resCountryDeaths);

        const resCountryCases = countryArray[0].cases;
        setcountryCases(resCountryCases);
        console.log("hiiii",countryCases);
      })
      .catch((err) => {
        console.log(err);
      });
  },[]);

  return { countryCases,countryDeaths };
};

CountryCard.tsx

const CountryCard = (props) => {
  const mappedLocation = useMappedLocation();
  const countryName = mappedLocation.country;

  return (
    <RectButton style={[styles.container,{ backgroundColor: "white" }]}>
      <Text style={[styles.textLocation,{ top: 15,left: 10 }]}>
        {countryName} /???
      </Text>
)
}

解决方法

这是一个关于如何重构这些阶段的伪代码建议,而不是采用 useEffect 和 useState 来执行更传统的只是异步的操作,然后是使用 useState 和 useEffect 来实现异步的“hook-style”模式结果可用于您的 UI。这段代码根本不可能运行,因为我无法访问您的环境来真正尝试它,但它可以让您了解如何重构它。如果状态需要被 UI 的多个部分使用,那么 useMappedLocation 钩子在祖先组件中分配一个 MappedLocation 变量是有意义的,结果通过 Context、Composition 或 Props 传递给后代。这将具有缓存结果的效果。

我还勾勒出第二个钩子如何消耗第一个钩子,因为我认为重新阅读了您的问题,这是您坚持原来方法的重点。然而,在多个地方嵌入 useMappedLocation 钩子会导致它被多次重新执行,并且与将其提升到祖先组件中相比不会从缓存中受益。

const apikey = "myapikey";

interface GeoEntry {
  address_components:[
    {types:("country"|"administrative_area_level_1")[]
      short_name:string,long_name:string
    }
  ]
}

interface MappedLocation {
  state:string,country:string
}

async function getLocation(){
  return await Location.getCurrentPositionAsync({});
}

async function getFirstGeoEntry() : Promise<GeoEntry>{
  const {latitude,longitude} = await getLocation();
  const response = await fetch(
          "https://maps.googleapis.com/maps/api/geocode/json?address=" +
            latitude +
            "," +
            longitude +
            "&key=" +
            apikey
        )
  const json = await response.json();
  return json.results[0]
}

function getStateNameLong(geoEntry:GeoEntry){
  return geoEntry.address_components.filter(
              (x: any) =>
                x.types.filter((t: Object) => t == "administrative_area_level_1")
                  .length > 0
            )[0].long_name
}

function getCountryNameShort(geoEntry:GeoEntry){
  return geoEntry.address_components.filter(
              (x: any) => x.types.filter((t: Object) => t == "country").length > 0
            )[0].short_name
} 

async function getMappedLocation() : Promise<MappedLocation>{
  const geoEntry = await getFirstGeoEntry();
  return {
    country:getCountryNameShort(geoEntry),state:getStateNameLong(geoEntry),}
}

const useMappedLocation = () => {
  const [mappedLocation,setMappedLocation] = useState<MappedLocation>(null);
  useEffect(() => {
    (async () => {
      setMappedLocation(await getMappedLocation())
    })()
  },[])
  return mappedLocation
}

以下是第二个钩子 ( useCountryData ) 可能使用第一个 ( useMappedLocation ) 的方式。请注意,useEffect 处理位置尚未到达的情况,而mappedLocation 位于依赖项数组中,以确保在mappedLocation 最终到达时useEffect 再次运行。

import { useMappedLocation } from './useMappedLocation';

export const useCountryData = () => {
  const [earliest2,setEarliest2] = useState([]);
  const [countryDeaths,setcountryDeaths] = useState(Number);
  const [countryCases,setcountryCases] = useState(Number);

  const mappedLocation = useMappedLocation()

  useEffect(() => {
    if(mappedLocation !== null){
      axios.get("https://coronavirus-19-api.herokuapp.com/countries")
        .then((response) => {
          setEarliest2(response.data);

          const countryArray = response.data.filter(
            (item) => item.country === mappedLocation.country
          );

          const resCountryDeaths = countryArray[0].deaths;
          setcountryDeaths(resCountryDeaths);

          const resCountryCases = countryArray[0].cases;
          setcountryCases(resCountryCases);
          console.log("hiiii",countryCases);
        })
        .catch((err) => {
          console.log(err);
        });
    }
  },[mappedLocation]);

  return { countryCases,countryDeaths };
};