• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

props.location.state.username zwaraca undefined - react native

0 głosów
421 wizyt
pytanie zadane 14 sierpnia 2021 w JavaScript przez sparklemo7ion Początkujący (360 p.)

Witam wszystkich. Mam problem z odczytaniem wartości props.location.state.username i props.location.state.partnerToken, które przekazuję z komponentu Login do HomeScreen poprzez komponent Redirect. Wartości zwracają undefined. 
 

Login.js

import React, { useEffect, useState } from "react";
import {
  TextInput,
  Text,
  StyleSheet,
  View,
  BackHandler,
  TouchableHighlight,
  Image,
} from "react-native";
import { withRouter, Redirect } from "react-router-native";
import global from "./style";
import firebase from "firebase";
import { useFonts } from "expo-font";
import AppLoading from "expo-app-loading";

function Login(props) {
  const [partnerUsername, setPartnerUsername] = useState(
    "Your partner username..."
  );
  const [username, setUsername] = useState("");
  const [partnerUsernameError, setPartnerUsernameError] = useState(false);
  const [partnerToken, setPartnerToken] = useState("");
  const [redirect, setRedirect] = useState(false);

  let propusername = props.location.state.username;

  useEffect(() => {
    console.log(
      "Imie:" +
        props.location.state.name +
        "Username:" +
        props.location.state.username
    );
    setUsername(props.location.state.username);

    const backAction = () => {
      props.history.push("/"); //wracamy do glownej
      return true; //musimy zreturnowac true -> patrz dokumentacja
    };

    const backHandler = BackHandler.addEventListener(
      //obsluga hardwarowego back buttona (tylko android)
      "hardwareBackPress",
      backAction
    );

    return () => backHandler.remove(); // przy odmontowywaniu
  }, []);

  const handleOnPress = () => {
    console.log("Partner username to find: " + partnerUsername);
    const ref = firebase.database.ref();
    var partnerToken;
    ref.child("usernames/" + partnerUsername).once("value", (snapshot) => {
      // jesli partner istnieje to wez jego token
      if (snapshot.exists()) {
        let data = snapshot.val();
        partnerToken = data.token;
        saveUserToDb(partnerToken);
      } else {
        setPartnerUsernameError(true);
        error = true;
      }
    });

    function saveUserToDb(partnerToken) {
      firebase
        .auth()
        .signInAnonymously()
        .then(() => {
          console.log("User signed in anonymously");

          firebase
            .database
            .ref("/users/" + firebase.auth().currentUser.uid)
            .update({
              id: firebase.auth().currentUser.uid,
              name: props.location.state.name,
              username: username,
              partnerUsername: partnerUsername,
              partnerToken: partnerToken,
            })
            .then(() => {
              console.log(
                "Data updated. and: username is: " +
                  username +
                  "partner topken is:" +
                  partnerToken
              );
              setPartnerToken(partnerToken);
              setRedirect(true);
            })
            .catch((error) => {
              console.error(error);
            });
        })
        .catch((error) => {
          if (error.code === "auth/operation-not-allowed") {
            console.log("Enable anonymous in your firebase console.");
          }

          console.error(error);
        });
    }
  };

  let [fontsLoaded] = useFonts({
    "GreatVibes-Regular": require("./assets/fonts/GreatVibes-Regular.ttf"),
  });
  if (!fontsLoaded) {
    return <AppLoading />;
  } else {
    return (
      <View style={styles.container}>
        <Text style={[styles.textHeader, { fontFamily: "GreatVibes-Regular" }]}>
          Enter your partner username
        </Text>
        <TextInput
          style={styles.input}
          value={partnerUsername}
          onChangeText={(e) => {
            setPartnerUsername(e);
          }}
        />
        <TouchableHighlight onPress={() => handleOnPress()}>
          <Image source={require("./assets/arrowRight.png")} />
        </TouchableHighlight>

        {partnerUsernameError && (
          <Text style={{ color: "red" }}>
            Partner username is not valid. Please try again.
          </Text>
        )}
        {redirect && (
          <Redirect
            to={{
              pathname: "/HomeScreen",
              state: { username: propusername },
            }}
          />
        )}
      </View>
    );
  }
}

export default withRouter(Login);

const styles = StyleSheet.create({
  container: {
    display: "flex",
    alignItems: "center",
    paddingTop: "59%",
    height: "100%",
    backgroundColor: global.primaryColor,
  },
  textHeader: {
    color: global.secondaryColor,
    fontSize: 48,
    marginBottom: "10%",
    textAlign: "center",
  },
  input: {
    width: "75%",
    height: 60,
    color: global.secondaryColor,
    fontSize: 18,
    padding: 16,
    marginBottom: "45%",
    borderRadius: 100,
    borderWidth: 1,
    borderColor: global.secondaryColor,
  },
});

Odczytuję to w komponencie HomeScreen:

 useEffect(() => {
    console.log("LOCATION STATE:" + props.location.state.username);
  }, []);

 

Dziwne jest to, że gdy zmienną redirect w komponencie Login zmieniam defaultowo na true, wykonuje się redirect i mogę normalnie odczytać wartości. Jednak gdy zmienna jest ustawiona na false i zmieniam ją dopiero w funkcji SaveToDb to wartości zwracają undefined. Jaki może być tego powód bo kończą mi się pomysły? 

Probowałem użyc hooka useLocation. Redirecta zamieniałem na props.history.push. Probowałem zmieniać lokalizację tego Redirecta w kodzie. Tak jak wspominałem wartości w HomeScreenie mogę odczytać tylko wtedy gdy redirect wykonuje się od razu, a nie jeśli jest robiony warunkowo. Routy w App.js wyglądają okej. Używam react native router do nawigacji. 

Bardzo proszę o pomoc, nie daje mi spokoju ten problem :/

komentarz 14 sierpnia 2021 przez ScriptyChris Mędrzec (190,190 p.)
redirect && (
          <Redirect
            to={{
              pathname: "/HomeScreen",
              state: { username: propusername },
            }}
          />
        )}

Jeśli problem występuje w tym fragmencie, to możesz tymczasowo zastąpić fragment po prawej stronie && i wypisać tam zmienne, które - wbrew oczekiwaniom - przyjmują wartość undefined. Jeśli problem nadal wystąpi, to wyeliminujesz winę samego <Redirect />. Być może to wina jakiegoś asynchronicznego zachowania związanego z re-renderingiem komponentu i/lub ustawianiem stanu.

Wg mnie, będzie można powiedzieć coś więcej, gdy sprawdzisz to miejsce.

komentarz 15 sierpnia 2021 przez sparklemo7ion Początkujący (360 p.)

@ScriptyChris, 

Zauważyłem coś bardzo dziwnego i to jest też może jest rozwiązanie tego problemu z postu wyżej. W fazie testów zmieniłem nieco kod:

import React, { useEffect, useState } from "react";
import {
  TextInput,
  Text,
  StyleSheet,
  View,
  BackHandler,
  TouchableHighlight,
  Image,
} from "react-native";
import { withRouter, Redirect } from "react-router-native";
import global from "./style";
import firebase from "firebase";
import { useFonts } from "expo-font";
import AppLoading from "expo-app-loading";

function SetPartnerUsername(props) {
  const [partnerUsername, setPartnerUsername] = useState(
    "Your partner username..."
  );
  const [username, setUsername] = useState("");
  const [partnerUsernameError, setPartnerUsernameError] = useState(false);
  const [partnerToken, setPartnerToken] = useState("");
  const [redirect, setRedirect] = useState(false);

  let propusername = props.location.state.username;

  useEffect(() => {
    console.log(
      "Imie:" +
        props.location.state.name +
        "Username:" +
        props.location.state.username
    );
    setUsername(props.location.state.username);

    const backAction = () => {
      props.history.push("/"); //wracamy do glownej
      return true; //musimy zreturnowac true -> patrz dokumentacja
    };

    const backHandler = BackHandler.addEventListener(
      //obsluga hardwarowego back buttona (tylko android)
      "hardwareBackPress",
      backAction
    );

    return () => backHandler.remove(); // przy odmontowywaniu
  }, []);

  const handleOnPress = () => {
    console.log("Partner username to find: " + partnerUsername);
    const ref = firebase.database.ref();
    var partnerToken;
    ref.child("usernames/" + partnerUsername).once("value", (snapshot) => {
      // jesli partner istnieje to wez jego token
      if (snapshot.exists()) {
        let data = snapshot.val();
        partnerToken = data.token;
        // saveUserToDb(partnerToken);
        firebase
          .auth()
          .signInAnonymously()
          .then(() => {
            console.log("User signed in anonymously");
          })
          .catch((error) => {
            if (error.code === "auth/operation-not-allowed") {
              console.log("Enable anonymous in your firebase console.");
            }

            console.error(error);
          });
      } else {
        setPartnerUsernameError(true);
        error = true;
      }
    });

    function saveUserToDb(partnerToken) {
      firebase
        .auth()
        .signInAnonymously()
        .then(() => {
          console.log("User signed in anonymously");

          firebase
            .database
            .ref("/users/" + firebase.auth().currentUser.uid)
            .update({
              id: firebase.auth().currentUser.uid,
              name: props.location.state.name,
              username: username,
              partnerUsername: partnerUsername,
              partnerToken: partnerToken,
            })
            .then(() => {
              console.log(
                "Data updated. and: username is: " +
                  username +
                  "partner topken is:" +
                  partnerToken
              );
              setPartnerToken(partnerToken);
              //setRedirect(true);
            })
            .catch((error) => {
              console.error(error);
            });
        })
        .catch((error) => {
          if (error.code === "auth/operation-not-allowed") {
            console.log("Enable anonymous in your firebase console.");
          }

          console.error(error);
        });
    }
  };

  let [fontsLoaded] = useFonts({
    "GreatVibes-Regular": require("./assets/fonts/GreatVibes-Regular.ttf"),
  });
  if (!fontsLoaded) {
    return <AppLoading />;
  } else {
    return (
      <View style={styles.container}>
        <Text style={[styles.textHeader, { fontFamily: "GreatVibes-Regular" }]}>
          Enter your partner username
        </Text>
        <TextInput
          style={styles.input}
          value={partnerUsername}
          onChangeText={(e) => {
            setPartnerUsername(e);
          }}
        />
        <TouchableHighlight onPress={(e) => handleOnPress(e)}>
          <Image source={require("./assets/arrowRight.png")} />
        </TouchableHighlight>

        {partnerUsernameError && (
          <Text style={{ color: "red" }}>
            Partner username is not valid. Please try again.
          </Text>
        )}
        {redirect &&
          (() => {
            console.log("USERNAME =>" + username);
          })}
      </View>
    );
  }
}

export default withRouter(SetPartnerUsername);

const styles = StyleSheet.create({
  container: {
    display: "flex",
    alignItems: "center",
    paddingTop: "59%",
    height: "100%",
    backgroundColor: global.primaryColor,
  },
  textHeader: {
    color: global.secondaryColor,
    fontSize: 48,
    marginBottom: "10%",
    textAlign: "center",
  },
  input: {
    width: "75%",
    height: 60,
    color: global.secondaryColor,
    fontSize: 18,
    padding: 16,
    marginBottom: "45%",
    borderRadius: 100,
    borderWidth: 1,
    borderColor: global.secondaryColor,
  },
});

okazuje się, że mimo, że pozbyłem się wszystkich redirectów i przekierowań sposobem props.history.push() jakimś cudem aplikacja przekierowuje mnie do strony głownej. Testując odkryłem że dzieje się to po wykonaniu: 

        firebase
          .auth()
          .signInAnonymously()
          .then(() => {
            console.log("User signed in anonymously");
          })
          .catch((error) => {
            if (error.code === "auth/operation-not-allowed") {
              console.log("Enable anonymous in your firebase console.");
            }

            console.error(error);
          });

jakby firebase automatycznie robił redirect na route "/". To może też tłumaczyć problem zwracania undefined przez props.location.state.username bo dane nie zostawały przekazywane przez komponent Redirecta, a przekierowanie było wykonywane przez firebase'a. Pytanie teraz tylko dlaczego? Nie pamiętam, żebym spotkał się z tym wcześniej..

komentarz 15 sierpnia 2021 przez ScriptyChris Mędrzec (190,190 p.)

Nie wiem czemu tak się dzieje. Możesz próbować debugować router, żeby dowiedzieć się, co konkretnie go triggeruje.

1 odpowiedź

0 głosów
odpowiedź 14 sierpnia 2021 przez Wiciorny Ekspert (282,600 p.)

https://pl.reactjs.org/docs/faq-state.html

Właściwości props (skrót od properties) i stan state są zwykłymi obiektami javascriptowymi. Przechowują informacje, które wpływają na wynik renderowania komponentu, jednak jest między nimi istotna różnica: właściwości props są przekazywane do komponentu (podobnie jak argumenty do funkcji), podczas gdy stan state jest zarządzany wewnątrz komponentu (podobnie jak zmienna w ciele funkcji).

komentarz 15 sierpnia 2021 przez sparklemo7ion Początkujący (360 p.)
Nie chodzi tu o state danego komponentu. Chodzi o atrybut obiektu location przy przekazywaniu atrybutów do komponentu niżej (props.location.state).

Podobne pytania

0 głosów
1 odpowiedź 327 wizyt
0 głosów
0 odpowiedzi 438 wizyt
pytanie zadane 3 stycznia 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)
0 głosów
1 odpowiedź 201 wizyt
pytanie zadane 31 sierpnia 2020 w JavaScript przez Bish0p Obywatel (1,940 p.)

93,692 zapytań

142,610 odpowiedzi

323,216 komentarzy

63,219 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...