• 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

Object Storage Arubacloud
0 głosów
132 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 (270,170 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ź 161 wizyt
0 głosów
0 odpowiedzi 342 wizyt
pytanie zadane 3 stycznia 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)
0 głosów
1 odpowiedź 109 wizyt
pytanie zadane 31 sierpnia 2020 w JavaScript przez Bish0p Obywatel (1,940 p.)

92,576 zapytań

141,426 odpowiedzi

319,650 komentarzy

61,961 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...