繁体   English   中英

为什么我的 useEffect function 只调用一次?

[英]Why is my useEffect function called only once?

我在FlatList中呈现Trips对象的列表。 所以我有一个名为Network的屏幕,其中有一个FlatList代表每个行程。 我的渲染方法:

return (
  <View style={styles.viewStyle}>
    <FlatList
      numColumns={1}
      horizontal={false}
      data={trips}
      keyExtractor={(item, index) => index.toString()}
      renderItem={({ item, index }) => (
        <View key={index}>
          <Trip trip={item} = />
        </View>
      )}
    />
  </View>
);

我的Trip组件内部是行程信息。 旅行的名称旅行的地理位置。 从这些地理位置我想得到这次旅行的城市和国家。 为此,我在我的useEffect function 中调用expoLocation API,每次行程:

let response = await Location.reverseGeocodeAsync({
        latitude,
        longitude,
      });

但是,似乎这个 function id 在我的FlatList中的所有行程中仅在最后一次行程中被调用一次。 这是我的Trip.js组件的样子:

import React, { useState, useEffect } from "react";
import { Text, TouchableOpacity } from "react-native";

import * as Location from "expo-location";

const Trip = ({ trip }) => {
  const [city, setCity] = useState(null);
  const [country, setCountry] = useState(null);
  const { latitude, longitude } = trip;
  console.log("trip name: ", trip.placeName);
  console.log("latitude: ", latitude);
  console.log("longitude: ", longitude);

  if (!trip) {
    return null;
  }

  useEffect(() => {
    console.log("calling use effect from trip summary: ", trip.placeName);
    async function fetchLocationName() {
      console.log("calling async function");
      let response = await Location.reverseGeocodeAsync({
        latitude,
        longitude,
      });
      console.log("response: ", response);
      setCity(response[0].city);
      setCountry(response[0].country);
    }
    fetchLocationName();
  }, [trip.id]);

  return (
    <TouchableOpacity style={{ flexDirection: "row", flexWrap: "wrap" }}>
      <Text>
        <Text style={styles.textStyle}>{trip.placeName} </Text>
        <Text style={styles.textStyle}>near </Text>
        <Text style={styles.textStyleHighlithed}>{city}, </Text>
        <Text style={styles.textStyleHighlithed}>{country} </Text>
      </Text>
    </TouchableOpacity>
  );
};

export default Trip;

我放了这么多console.log ,因为我想确定我有trip.longitudetrip.latitude ,我确实有。 我在控制台上看到的打印内容:

latitude:  126.3936269
longitude:  59.3397108
latitude:  71.34165024
longitude:  129.7406225
calling use effect from trip summary:  trip one
calling async function
calling use effect from trip summary:  second trip
calling async function
response:  Array [
  Object {
    "city": "some city",
    "country": "some country",
    ...
  },
]

事实上,在我的屏幕上,我只看到了最后一次旅行的城市和国家。

如何确保每次旅行都调用我的useEffect function,而不仅仅是最后一次?

您的日志显示 useEffect 被调用了两次:

calling use effect from trip summary:  trip one
calling async function
calling use effect from trip summary:  second trip
calling async function

所以问题不在于 useEffect 。 问题是您永远不会从Location.reverseGeocodeAsync为您的一个调用获得返回值。

Expo 文档中查看 Location ,您可以看到以下警告:

Note: Geocoding is resource consuming and has to be used reasonably. Creating too many requests at a time can result in an error, so they have to be managed properly. It's also discouraged to use geocoding while the app is in the background and its results won't be shown to the user immediately.

expo-location 的 iOS 代码中,如果调用过多,则会打印以下行: Rate limit exceeded - too many requests 如果你看到那条线,你需要设法隔开这些请求。

reverseGeocodeAsync 还接受一个选项参数,允许您改为使用 Google 的位置服务 ( { useGoogleMaps: true } )。

总而言之,这里有两件事可以尝试。 您可以重写您的 useEffect 以明确捕获错误,以防它们没有出现(为简洁起见,删除了日志):

  useEffect(() => {
    async function fetchLocationName() {
      try {
        const response = await Location.reverseGeocodeAsync({
          latitude,
          longitude,
        });
        setCity(response[0].city);
        setCountry(response[0].country);
      } catch (error) { 
        console.error(error);
      };
    }
    fetchLocationName();
  }, [trip.id]);

如果您看到速率限制错误,您将需要构建一个请求队列,将调用间隔足够长以避免这种情况。

或者你可以尝试使用谷歌的服务,除了调用reverseGeocodeAsync的那一行之外,它是相同的:

  useEffect(() => {
    async function fetchLocationName() {
      try {
        const response = await Location.reverseGeocodeAsync({
          latitude,
          longitude,
        }, { useGoogleMaps: true });
     ...

你可以这样写你的异步 function :试试这个

useEffect(async()=>{
console.log("calling use effect from trip summary: ", trip.placeName);
let response = await Location.reverseGeocodeAsync({
        latitude,
        longitude,
      });
 console.log("response: ", response);
      setCity(response[0].city);
      setCountry(response[0].country);
},[trip.id])

useEffect在组件在屏幕上呈现后运行,作为您放入数组中的依赖项的效果,请在问题中添加 TRIP 组件的所有控制台日志。

 console.log("trip name: ", trip.placeName);
-------------------------
console.log("calling use effect from trip summary: ", trip.placeName);

即使您实现了您想要的功能,从 flatlist 的每个项目中调用 api 也不是一个好方法,因为它会降低性能。 更好的方法是在某些用户交互事件中调用 api 以获得特定的纬度和经度集。 这将是单一的、同步的和高性能的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM