Baryarte
Baryarte

Reputation: 63

Firestore "get" function getting executed multiple times

I'm a newbie at React-Native and Firebase and i'm using Firebase Cloud Firestore for a project. I'm trying to get filtered data from the database statically (as i'm learning to use it for now), but somehow my function is getting executed multiple times, the numbers of readings is increasing rapidly and i'm having some random errors too. I would like to know what's wrong.

Here is my code for the file that only deals with the database (Firestore.js):

import React, { useState, useEffect } from "react";
import { ActivityIndicator } from "react-native";
import * as firebase from "firebase";
import "firebase/firestore";

function onResult(QuerySnapshot) {
  console.log("Pegamos a coleção de Animais.");
}

function onError(error) {
  console.error(error);
}

export function GetAnimalsByEspecie(especie) {
  const [loading, setLoading] = useState(true);
  const [animais, setAnimais] = useState([]);

  console.log("entrou Especie");
  const subscriber = firebase
    .firestore()
    .collection("Animal")
    .where("especie", "==", especie)
    .get()
    .then((querySnapshot) => {
      const animaisList = [];

      querySnapshot.forEach((documentSnapshot) => {
        animaisList.push({
          ...documentSnapshot.data(),
          key: documentSnapshot.id,
        });
      });

      setAnimais(animaisList);
      setLoading(false);
    });

  if (loading) {
    console.log("loading");
    return <ActivityIndicator />;
  }

  return animais;
}

export function GetAnimalsByNome(nomeAnimal) {
  const [loading, setLoading] = useState(true);
  const [animais, setAnimais] = useState([]);

  console.log("entrou nome nooome");
  const subscriber = firebase
    .firestore()
    .collection("Animal")
    .where("nome", "==", nomeAnimal)
    .get()
    .then((querySnapshot) => {
      const animaisList = [];

      querySnapshot.forEach((documentSnapshot) => {
        animaisList.push({
          ...documentSnapshot.data(),
          key: documentSnapshot.id,
        });
      });

      setAnimais(animaisList);

      setLoading(false);
    });

  if (loading) {
    console.log("loading");
    return <ActivityIndicator />;
  }

  return animais;
}

export default function GetAnimals() {
  const [loading, setLoading] = useState(true);
  const [animais, setAnimais] = useState([]);

  useEffect(() => {
    console.log("entrou listener");
    const subscriber = firebase
      .firestore()
      .collection("Animal")
      //   .where('')
      .onSnapshot((querySnapshot) => {
        const animaisList = [];

        querySnapshot.forEach((documentSnapshot) => {
          animaisList.push({
            ...documentSnapshot.data(),
            key: documentSnapshot.id,
          });
        });

        setAnimais(animaisList);
        setLoading(false);
      });

    return () => subscriber();
  }, []);

  

  if (loading) {
    console.log("loading");
    return <ActivityIndicator />;
  }

  return animais;
}

Here is my code for the file that displays data on the screen (index.js):

import React, { useState } from "react";
import {
  View,
  Text,
  KeyboardAvoidingView,
  StyleSheet,
  Image,
  TextInput,
  TouchableHighlight,
  ScrollView,
  Button,
  ActivityIndicator,
  FlatList,
} from "react-native";
import { SearchBar } from "react-native-elements";
import { createStackNavigator } from "@react-navigation/stack";
import { SafeAreaView } from "react-native-safe-area-context";
import SubmitButton from "../../shared/SubmitButton";
import FocusAwareStatusBar from "../../shared/StatusBar";

import GetAnimals, {GetAnimalsByEspecie, GetAnimalsByNome} from "../../db/Firestore";



const styles = StyleSheet.create({
  background: {
    flex: 1,
    backgroundColor: "#fafafa",
    alignItems: "center",
    justifyContent: "center",
  },
  regform: {
    alignSelf: "stretch",
  },
  textInput: {
    fontFamily: "Roboto_400Regular",
    fontSize: 14,
    alignSelf: "stretch",
    paddingLeft: 12,
    marginHorizontal: 16,
    color: "#000000",
    borderBottomColor: "#dcdcdc",
    borderBottomWidth: 0.8,
    paddingBottom: 8,
  },
  label: {
    alignSelf: "stretch",
    marginTop: 28,
    marginBottom: 32,
    paddingLeft: 28,
    color: "#589b9b",
  },
  container: {
    flex: 1,
    justifyContent: "center",
    alignSelf: "center",
    height: 128,
    width: 128,
    backgroundColor: "#fff",
    elevation: 4,
  },
  button: {
    alignItems: "center",
    backgroundColor: "#f1f2f2",
    paddingTop: 44,
    paddingBottom: 48,
  },
  infobox: {
    backgroundColor: "#cfe9e5",
    borderRadius: 4,
    height: 80,
    width: 328,
    marginTop: 16,
    marginHorizontal: 16,
    justifyContent: "space-evenly",
    alignContent: "center",
  },
  infotext: {
    fontFamily: "Roboto_400Regular",
    fontSize: 14,
    color: "#434343",
    paddingHorizontal: 15,
    marginVertical: 11,
    textAlign: "center",
  },
});


export default function Animais() {

  var animais = GetAnimalsByEspecie('shitzu');

  const search = () => {
    const [searchQuery, setSearchQuery] = useState("");

    return (
    <SearchBar
      placeholder="Escreva aqui..."
      onChangeText={""}
      value={searchQuery}
    />)
  };

  

  return (
    
    <SafeAreaView style={{ flex: 1 }}>
      <FocusAwareStatusBar barStyle="light-content" backgroundColor="#88c9bf" />

      <KeyboardAvoidingView style={styles.background}>
        <View>
          <Text>Animais</Text>
          <FlatList
            ListHeaderComponent={''}
            data={animais}
            renderItem={({ item }) => (
              <View
                style={{
                  height: 50,
                  width: 350,
                  flex: 1,
                  alignItems: "center",
                  justifyContent: "center",
                }}
              >
                <Text>Animal ID: {item.id}</Text>
                <Text>Animal Name: {item.nome}</Text>
              </View>
            )}
          />
        </View>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

I'm not using SearchBar yet, for now i'm just trying to fetch and display the data which have 'especies' field equal to 'shitzu' from the database. Sometimes I get the correct information, sometimes I get errors.

Thanks for the help.

Upvotes: 0

Views: 557

Answers (1)

Jacob
Jacob

Reputation: 78850

You should put your fetches inside of a useEffect so you can make it run only once. Otherwise, when your fetch callbacks set state, you'll get a re-render, and your fetch code will run again. Also, it looks like GetAnimalsByEspecie, since it invokes hooks, should itself be a hook. For example:

export function useAnimalsByEspecie(especie) {
  const [loading, setLoading] = useState(true);
  const [animais, setAnimais] = useState([]);

  useEffect(() => {
    const subscriber = firebase
      .firestore()
      .collection("Animal")
      .where("especie", "==", especie)
      .get()
      .then((querySnapshot) => {
        const animaisList = [];
        querySnapshot.forEach((documentSnapshot) => {
          animaisList.push({
            ...documentSnapshot.data(),
            key: documentSnapshot.id,
          });
        });

        setAnimais(animaisList);
        setLoading(false);
      });
  }, [especie]);

  return [animais, loading];
}

...which would be used like:

function Animais() {

  var [animais, isLoading] = useAnimalsByEspecie('shitzu');

  const search = () => {
    const [searchQuery, setSearchQuery] = useState("");

    return (
    <SearchBar
      placeholder="Escreva aqui..."
      onChangeText={""}
      value={searchQuery}
    />)
  };

  if (isLoading) {
    return <ActivityIndicator />;
  }

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <FocusAwareStatusBar barStyle="light-content" backgroundColor="#88c9bf" />

      <KeyboardAvoidingView style={styles.background}>
        <View>
          <Text>Animais</Text>
          <FlatList
            ListHeaderComponent={''}
            data={animais}
            renderItem={({ item }) => (
              <View
                style={{
                  height: 50,
                  width: 350,
                  flex: 1,
                  alignItems: "center",
                  justifyContent: "center",
                }}
              >
                <Text>Animal ID: {item.id}</Text>
                <Text>Animal Name: {item.nome}</Text>
              </View>
            )}
          />
        </View>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

Upvotes: 1

Related Questions