Правильный путь к l oop и исправлению объекта без повторного рендеринга циклов - PullRequest
1 голос
/ 30 апреля 2020

Мой основной компонент приложения вызывает в JSON объекте мест с их широтой / долготой.

Я рендерил этот JSON объект с помощью FlatList, и все это работает нормально. Приложение также вытягивает местоположение устройства, чтобы я мог отсортировать эти данные по информации, отсортированной по расстоянию.

В настоящее время я пытаюсь изменить этот объект JSON, чтобы добавить расстояние от устройства до места проведения и положить это обратно в FlatList, но это, кажется, вызывает бесконечный повторный рендеринг l oop, и я на самом деле не думаю, что он способен вызвать мои проверки расстояния.

Это мой компонент здесь. Я прокомментировал дистанционную работу, которая, как мне показалось, была причиной, но все равно кажется, что она дает бесконечный повторный рендеринг l oop

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

import * as Location from "expo-location";

import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";

import pubData from "../data/pubs.json";

function Item({ id, name, location, alternatives, navigation, sorted }) {
  if (sorted) {
    return (
      <TouchableOpacity
        onPress={() =>
          navigation.navigate("Pub", {
            id: id,
            name: name,
            location: location,
            alternatives: alternatives,
          })
        }
        style={[styles.item]}
      >
        <View style={styles.itemLeft}>
          <Text style={styles.name}>{name}</Text>
          <Text style={styles.location}>in {location}</Text>
        </View>
        <View style={styles.itemRight}>
          <Text style={styles.distance}>XX miles</Text>
        </View>
      </TouchableOpacity>
    );
  } else {
    return (
      <TouchableOpacity
        onPress={() =>
          navigation.navigate("Pub", {
            id: id,
            name: name,
            location: location,
            alternatives: alternatives,
          })
        }
        style={[styles.item]}
      >
        <View style={styles.itemFull}>
          <Text style={styles.name}>{name}</Text>
          <Text style={styles.location}>in {location}</Text>
        </View>
      </TouchableOpacity>
    );
  }
}

function distance(lat1, lon1, lat2, lon2) {
  if (lat1 == lat2 && lon1 == lon2) {
    return 0;
  } else {
    var radlat1 = (Math.PI * lat1) / 180;
    var radlat2 = (Math.PI * lat2) / 180;
    var theta = lon1 - lon2;
    var radtheta = (Math.PI * theta) / 180;
    var miles =
      Math.sin(radlat1) * Math.sin(radlat2) +
      Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
    if (miles > 1) {
      miles = 1;
    }
    miles = Math.acos(miles);
    dmilesimilesst = (miles * 180) / Math.PI;
    miles = miles * 60 * 1.1515;
    return miles;
  }
}

export default function FullList({ navigation }) {
  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);
  const [distances, setDistances] = useState([]);
  const [sorted, setSorted] = useState(false);

  useEffect(() => {
    (async () => {
      let { status } = await Location.requestPermissionsAsync();
      if (status !== "granted") {
        setErrorMsg("Permission to access location was denied");
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);
    })();
  });

  let text = "Waiting...";
  if (errorMsg) {
    text = errorMsg;
  } else if (location) {
    text = JSON.stringify(location);
    setSorted(true);
  }

  // if (sorted) {
  //   let currentDistance;
  //   Object.entries(pubData).map(([key, pub]) => {
  //     setDistances([
  //       ...distances,
  //       {
  //         id: pub.id,
  //         miles: (currentDistance = distance(
  //           pub.lat,
  //           pub.long,
  //           location.coords.latitude,
  //           location.coords.longitude
  //         )),
  //       },
  //     ]);
  //   });
  // }

  return (
    <View style={styles.container}>
      <Text style={styles.default}>
        Select the venue you would like to find an alternative to
      </Text>

      <FlatList
        data={pubData}
        renderItem={({ item }) => (
          <Item
            id={item.id}
            name={item.name}
            location={item.location}
            alternatives={item.alternatives}
            navigation={navigation}
            sorted={sorted}
          />
        )}
        keyExtractor={(item) => item.id}
      />
    </View>
  );
}

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

Я думаю, что виноват код:

useEffect(() => {
    (async () => {
      let { status } = await Location.requestPermissionsAsync();
      if (status !== "granted") {
        setErrorMsg("Permission to access location was denied");
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);
    })();
  });

Вы вызываете хук useEffect без списка зависимостей (второй аргумент).

useEffect(() => { setLocation(...) }) будет срабатывать при каждом рендере. Вы в основном визуализируете компонент, запрашиваете местоположение и обновляете состояние, которое (точнее, обновление состояния) вызывает повторную визуализацию.

Если вы добавляете пустой список зависимостей (useEffect(() => { setLocation(...) }, [])), Функция, переданная в useEffect, будет срабатывать только при монтировании, что, вероятно, и вам нужно.

1 голос
/ 30 апреля 2020

Ваш useEffect в Fulllist вызывает повторные рендеры.

Чтобы он запускался только один раз при монтировании компонента (например, componentDidMount жизненный цикл), добавьте пустой массив зависимостей в качестве второго параметра

  useEffect(() => {

   /* your code */

  }, [] /* here */);

Подробнее читайте в Реагировать на документы.

...