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

Wyskakujące okno z prośbą o dane podczas działania funkcji React

VPS Starter Arubacloud
0 głosów
194 wizyt
pytanie zadane 20 maja 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)

Jestem ciekaw w jaki sposób podczas działania funkcji, mogę wyświetlić użytkownikowi zapytanie o jakieś dane i nie przerywając tej funkcji czekać na nie. Po ich dostaniu wznowić jej działanie w tym samym punkcie, w którym się zatrzymała. Na konkretnym przykładzie chodzi mi np o obsłużenie błędu  'account-exists-with-different-credential', który wyrzuca firebase przy logowaniu facebookiem, jeśli mamy już konto. 
 

// Step 1.
// User tries to sign in to Facebook.
auth.signInWithPopup(new firebase.auth.FacebookAuthProvider()).catch(function(error) {
  // An error happened.
  if (error.code === 'auth/account-exists-with-different-credential') {
    // Step 2.
    // User's email already exists.
    // The pending Facebook credential.
    var pendingCred = error.credential;
    // The provider account's email address.
    var email = error.email;
    // Get sign-in methods for this email.
    auth.fetchSignInMethodsForEmail(email).then(function(methods) {
      // Step 3.
      // If the user has several sign-in methods,
      // the first method in the list will be the "recommended" method to use.
      if (methods[0] === 'password') {
        // Asks the user their password.
        // In real scenario, you should handle this asynchronously.
        var password = promptUserForPassword(); // TODO: implement promptUserForPassword.
        auth.signInWithEmailAndPassword(email, password).then(function(user) {
          // Step 4a.
          return user.linkWithCredential(pendingCred);
        }).then(function() {
          // Facebook account successfully linked to the existing Firebase user.
          goToApp();
        });
        return;
      }
      // All the other cases are external providers.
      // Construct provider object for that provider.
      // TODO: implement getProviderForProviderId.
      var provider = getProviderForProviderId(methods[0]);
      // At this point, you should let the user know that they already has an account
      // but with a different provider, and let them validate the fact they want to
      // sign in with this provider.
      // Sign in to provider. Note: browsers usually block popup triggered asynchronously,
      // so in real scenario you should ask the user to click on a "continue" button
      // that will trigger the signInWithPopup.
      auth.signInWithPopup(provider).then(function(result) {
        // Remember that the user may have signed in with an account that has a different email
        // address than the first one. This can happen as Firebase doesn't control the provider's
        // sign in flow and the user is free to login using whichever account they own.
        // Step 4b.
        // Link to Facebook credential.
        // As we have access to the pending credential, we can directly call the link method.
        result.user.linkAndRetrieveDataWithCredential(pendingCred).then(function(usercred) {
          // Facebook account successfully linked to the existing Firebase user.
          goToApp();
        });
      });
    });
  }
});

Dokładnie chodzi mi o fragment treść w komentarzu pod:
 

var provider = getProviderForProviderId(methods[0]);

W jaki spsób coś takiego zrealizować ?

komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)

Tak, wartość "Go on" lub "Don't Login" będzie wynikiem rozwiązania Promisa. Ale to nie jest koniec, ponieważ coś musi jeszcze zareagować na ten stan Promisa. Tutaj wkracza metoda then, do której przekazujesz (opcjonalnie) dwa callbacki i tam wykonujesz akcję, która ma zadziać się, gdy czynność asynchroniczna (w Twoim przypadku użytkownik dokonujący wyboru na popupie) zostanie zakończona (pozytywnie lub negatywnie).

Zauważ, że metoda auth.signInWithPopup z kawałka kodu, który wstawiłeś też ma podpięty then, do którego przekazany jest callback, który będzie zawołany, gdy Promise zwrócony przez auth.signInWithPopup zostanie rozwiązany.

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

Aha.. chyba rozumiem. 

Czy taki zapis 
 

createAudioFileAsync(audioSettings).then( resp => {
successCallback(resp)
}).catch(err => {
failureCallback(err)
})

jest równoważny temu :

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

 jeśli te funkcje success i failure są gdzieś wyżej zdefiniowane ?
 

Bo prawdę mówiąć tego Promise chciałem napisać w innym pliku i go zimportować tam gdzie próbuję się zalogować.

komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)

Zapis z catch w tym przypadku jest bardziej elastyczny, bo złapie też błąd jeśli wystąpi w funkcji successCallback.

Z importem nie powinieneś mieć problemu.

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

Hm... Napisałem taki promise
 

import React from 'react'
import AskAboutPassword from './askAboutPassword/askAboutPassword'

const passwordAskPromise = new Promise((resolve, reject) => {
    const setDecision = decision => {
        if(decision)
            resolve(decision)
        else
            reject(decision)
        }
        return(<AskAboutPassword setDecision={(value) => setDecision(value)}/>)
})

export default passwordAskPromise;
import React from 'react'

import styles from './askAboutPassword.module.css'

const AskAboutPassword = props =>{ 

    return (
        <div className={styles.AskAboutPasswordContainer}>
            <button onClick={() => props.setDecision(true)}>YES</button>
            <button onClick={() => props.setDecision(false)}>NO</button>
        </div>
    )
}

export default AskAboutPassword;
                    if(methods[0] === 'password') {
                        console.log("he")
                        passwordAskPromise.then(() => {
                            console.log("poszlo")
                        }).catch(() => {
                            console.log("niet")
                        })
                        
                        return ;
                    }

I prawdę mówiąc nie za bardzo działa. Konsola wyświetla mi "he" i na tym jest koniec..

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

Trochę zmieniłem tj. :
 

    ReactDOM.render(<AskAboutPassword setDecision={(value) => setDecision(value)}/>, document.getElementById("popup"))

i w index.html dodałem :
 

  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="popup"></div>

  </body>

Jednak nie jestem do końca pewny czy w taki sposób miałem to napisać, ponieważ ten mój popup faktycznie wypisuje wartości "poszło" i "niet" w konsoli, jednak jest on na oknie cały czas..

1 odpowiedź

+1 głos
odpowiedź 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)
wybrane 20 maja 2020 przez poldeeek
 
Najlepsza

I prawdę mówiąc nie za bardzo działa. Konsola wyświetla mi "he" i na tym jest koniec..

Trochę nie rozumiem 8 linii w tym:

const passwordAskPromise = new Promise((resolve, reject) => {
    const setDecision = decision => {
        if(decision)
            resolve(decision)
        else
            reject(decision)
        }
        return(<AskAboutPassword setDecision={(value) => setDecision(value)}/>) // co to robi?
})

Nie możesz zwrócić czegoś z callbacka przekazanego do konstruktora Promisa. Zadaniem tego callbacka jest wywołanie resolve lub reject. Dopiero to skutkuje rozwiązaniem promisa. Promise powinieneś stworzyć w momencie, gdy otwierasz/pokazujesz popup (początek akcji asynchronicznej).


mój popup faktycznie wypisuje wartości "poszło" i "niet" w konsoli, jednak jest on na oknie cały czas..

A czy chowasz/zamykasz ten popup na wciśnięcie przycisku?

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

Poprawiłem to na 

    ReactDOM.render(<AskAboutPassword setDecision={(value) => setDecision(value)}/>, document.getElementById("popup"))
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="popup"></div>

  </body>

Wprawdzie sama logika działa,jednak coś czuje, że to też nie o to chodziło...

A w logice logowania działa samo logowanie, ponieważ faktycznie logujemnie do konta, jednak nie działa łączenie ze sobą kont w firebase. Wyrzuca taki błąd : 
 

Uncaught TypeError: user.linkWithCredential is not a function
                    //jesli login i haslo
                    if(methods[0] === 'password') {
                        console.log("he")
                        passwordAskPromise.then((password) => {
                            console.log(password)
                            firebase.auth().signInWithEmailAndPassword(email, password).then(function(user) {
                                return user.linkWithCredential(pendingCred).then(()=>{console.log("nic")})
                              })
                        }).catch(() => {
                            console.log("niet")
                        })
                        
                        return ;
                    }

Gdzie kod napisałem tak samo jak jest w dokumentacji..



 

komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)

Może zrobiłeś jakąś literówkę? Wyświetl w konsoli zmienną user - zobacz czym jest (+ prototyp, bo tam powinna być metoda linkWithCredential).

I podaj linka gdzie znalazłeś użycie metody user.linkWithCredential.

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

https://firebase.google.com/docs/auth/web/facebook-login

W tej samej użyli funkcji. Pod krokiem 4a.
obiekt user - 

1
komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)

Hmm, może zrobili update API, a w instrukcji tego nie uwzględnili. Z tego co widzę w kodzie API, to metoda signInWithEmailAndPassword zwraca Promisa z wartością o interfejsie UserCredential, a tam z kolei jest już User, a on powinien zawierać metodę linkWithCredential.

Sprawdź więc czy ta metoda znajduje się w zagnieżdżonym property user (na screenie jest do niej przypisany obiekt P) i jej prototypie.

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

Poszło :D

                            firebase.auth().signInWithEmailAndPassword(email, password).then(function(user) {
                                console.log('user',user)
                                return user.user.linkWithCredential(pendingCred);
                              })

Moje mam nadzieje już ostatnie pytanie jest odnośnie tego promise, który tworzy się razem z pokazaniem popupa. Szukałem trochę, ale wszędzie jest tylko jak zrobić popup przy uzyciu state. A nie mam zielonego pojęcia jak się zabrać do tego w działającej funkcji przy użyciu promise. W sensie nie wiem jak wyrenderować ten komponent...

komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)

Nie za bardzo wiem jak pomóc Ci z renderowaniem komponentu, bo nie znam Reacta. Co masz na myśli przez "jak się zabrać do tego w działającej funkcji przy użyciu promise"? Skoro pokazuje Ci się popup i możesz na nim klikać w przyciski, a to odpowiednio spełnia lub odrzuca promise, to w czym jest problem? :)

P.S. Zamień user.user.linkWithCredential na userCredential.user.linkWithCredential i analogicznie nazwę parametru callbacka (w pierwszej linijce) z user na userCredential, ponieważ wg API metoda signInWithEmailAndPassword nie zwraca obiektu typu User tylko UserCredential.

komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)
Chodzi mi o to, że nie wiem jak pokazać ten popup w momencie uruchamiania się promise.
komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)
Pokaż aktualny kod: promisa, pokazania popupa i obsługi rozwiązującej promisa po kliknięciu w przycisk.
komentarz 20 maja 2020 przez poldeeek Mądrala (5,980 p.)

Promise
 

const passwordAskPromise = new Promise((resolve, reject) => {
    const setDecision = decision => {
        if(decision)
            resolve(decision)
        else
            reject(decision)
        }
    
    ReactDOM.render(<AskAboutPassword setDecision={(value) => setDecision(value)}/>, document.getElementById("popup"))
})

Popup



const AskAboutPassword = props =>{ 

    const [password, setPassword] = useState('')

    return (
        <div className={styles.AskAboutPasswordContainer}>
            <input type="text" value={password} onChange={(e)=>setPassword(e.target.value)}/>
            <button onClick={() => props.setDecision(password)}>YES</button>
            <button onClick={() => props.setDecision(false)}>NO</button>
        </div>
    )
}

i html dodałem diva w głównym pliku

  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="popup"></div>

  </body>

Obługa jeśli klikniemy Yes to wysyła hasło do promise jak decisione, a jesli nie to nie to wysyla false.


Myślałem, że dodać stan w Redux i nim manipulować wtedy pokazaniem, schowaniem popupa, którego renderuje właśnie przez React.Dom(), ale samo użycie ReactDom() wydaje mi się przekombinowane...
 

komentarz 20 maja 2020 przez ScriptyChris Mędrzec (190,190 p.)

Spróbuj w ten sposób:

function openPopup() {
  let resolver = () => {};
  let rejecter = () => {};

  const setDecision = decision => {
      if(decision) {
          resolver(decision); // zawołaj "uzewnętrzniony" resolve
      } else {
          rejecter(decision); // zawołaj "uzewnętrzniony" reject
      }
  }

  ReactDOM.render(
        <AskAboutPassword setDecision={(value) => setDecision(value)}/>, 
        document.getElementById("popup")
  )

  return new Promise((resolve, reject) => {
    resolver = resolve; // przypisz referencje resolve do zewnętrznej zmiennej
    rejecter = reject; // przypisz reference reject do zewnętrznej zmiennej
  });
}

openPopup().then(onSuccess /* ... */, onFail /* ... */);

Co do pytania o stosowność użycia ReactDOM.render, to nie pomogę, bo jak wspomniałem nie mam doświadczenia z Reactem.

Podobne pytania

0 głosów
1 odpowiedź 135 wizyt
pytanie zadane 19 maja 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)
0 głosów
0 odpowiedzi 303 wizyt
pytanie zadane 25 kwietnia 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)
0 głosów
1 odpowiedź 202 wizyt
pytanie zadane 22 kwietnia 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)

92,454 zapytań

141,263 odpowiedzi

319,099 komentarzy

61,854 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

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 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!

...