【问题标题】:How to use variables from exported constants in other files?如何在其他文件中使用导出常量中的变量?
【发布时间】:2021-05-07 23:36:20
【问题描述】:

我将const 导出到一个文件useLocation.tsx 中,在该文件中获取用户的位置并检索用户的县、州/省和国家/地区。我还在另一个文件useCountryData.tsx 中有一个导出的const,我在其中从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>
)
}

【问题讨论】:

  • 您不需要使用.tsx,因为您不使用 tsx 表达式(在您的打字稿/javascript 中使用“html 代码”)。一般来说,如果你想使用导出的常量,你需要将它们导入你的文件import { myConst } from 'myFile'
  • 当你没有进行任何实际的 React DOM 操作时,这看起来就像你使用了 React 代码和模式。因此,一切都比它需要的更加混乱。您正在执行的任务是简单的异步操作,可能导致分配作为承诺的 const 值。然后,这些承诺值可以导出并等待,无论您关心在最终解决该特定值时使用该值。了解 await 和 async 并努力删除代码中对 useEffect 和 useState 的所有引用。它们是多余的并造成了问题。
  • @messerbill 我实际上正在使用 react-native typescript 进行移动开发。我不明白你不使用.tsx. 的意思我已经在导入常量,但我不知道我是否正确传递了countryNameshort。我已经更新了上面的代码。
  • @cefn 我需要使用 React DOM 进行移动开发吗?我只是想知道如何在useLocation.tsxuseCountryData.tsx 中使用countryNameshort,也许使用React 道具。
  • 我建议阅读更多关于javascripttypescript 之间的区别以及何时使用jsxtsxreactjs.org/docs/introducing-jsx.html干杯

标签: javascript typescript react-native constants


【解决方案1】:

这里是关于如何重构这些阶段的伪代码建议,而不采用 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 在依赖数组中以确保 useEffect 在 mappedLocation 最终到达时第二次运行。

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 };
};

【讨论】:

  • 已更新以添加第二个挂钩如何使用第一个。
  • 非常感谢,非常感谢您抽出宝贵的时间。我没有意识到我的代码模式被错误地使用了,你清理了我的代码很多。我只有一个问题 - 每当我第一次加载应用程序而无法访问位置时,前端的位置名称就不会加载。我必须保存我的项目,然后它们会在大约一分钟后加载。但是,当我第二次加载该应用程序时,一切正常。我怎样才能解决这个问题?我还更新了我的代码,以便您更好地理解我的答案。我是否需要为此使用 useEffect 来处理这种情况以使其第二次运行?
  • 在我分享的代码中,提供 useMappedLocation() 的 useEffect 只会运行一次(参见dev.to/rozenmd/understanding-useeffect-the-dependency-array-obg)。如果第一次失败,则不会触发重试。它仍然未设置。所以问题是 - 如果 getMappedLocation 在 useEffect() 中抛出,重试行为应该是什么?捷径包括:周期性重试,或者周期性重试,直到mappedLocation有值然后停止。如果您已将代码向前移动,也许您可​​以参考最新代码提出这个不同的问题。
  • 我会让 getLocation() 抛出错误。这可以添加到嵌入在 useMappedLocation() 中的异步函数中的 catch 子句中。当你捕捉到传播的错误时,你需要决定如何让调用者看到它(例如,mappedLocation 的特殊值)。您可以使用严格的值 false 吗?然后,这是您的渲染函数中内联的 const 值,因此您可以将其用于控制​​流 - 改为使用特殊视图为组件提供服务。不过,它最终只会以 false 值解决,因此您也将有一个中间 null 状态来处理。
  • 这不是处理故障的方法,而是检查故障的方法。当您尝试创建一个简单的 useMappedLocation() 挂钩时处理它的问题是一个单独的问题。我的评论提出了如何通过钩子的所有异步层传递位置调用的“失败”状态。这是钩子调用者如何使用“标准”接口找出没有映射位置的方法。可能有很多检查失败的好方法,但我建议使用 EAFP 而不是 LBYL 策略来通知任何失败以避免此类逻辑中的 TOCTTOU 错误.
猜你喜欢
  • 2021-07-29
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 2015-06-15
  • 2021-10-21
  • 2018-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多