Async-Funktionen in useEffect () einbinden Hook in React

Oct 04 2020

Ich beende eine App, in der ich meinen GoogleMap-API-Schlüssel hinter meiner sicheren API verstecken möchte. Ich möchte den API-Schlüssel abrufen, sobald ich überprüft habe, ob ich einen authentifizierten Benutzer habe. Das Problem ist, dass zwischen den asynchronen Aufrufen Änderungen nicht mit der Statusänderung berücksichtigt werden.

Das mache ich:

export default function App() {
  const [dateRange, setDateRange] = useState(initialDateRange);
  const [formState, updateFormState] = useState(initialFormState);
  const [user, setUser] = useState(null);
  const [googleApiKey, setGoogleApiKey] = useState(null);

  useEffect(() => {
    async function updateAuth() {
      try {
        await checkUser();
        await getGoogleApiKey();
        await setAuthListener();
      } catch (error) {}
    }
    updateAuth();
  }, []);

  async function checkUser() {
    try {
      const user = await Auth.currentAuthenticatedUser();
      setUser(user);
      if (user !== authenticatedUser) {
        updateFormState(() => ({
          ...formState,
          authenticatedUser: user
        }));
      }
    } catch (error) {
      console.log(error);
    }
  }

  async function getGoogleApiKey() {
    const googleApiUrl = `${process.env.REACT_APP_API_PATH}apikey?googleapikey=true`; 
    try {
      console.log('USER_USER_USER', user);
      const apiKey = await fetch(googleApiUrl, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          Authorization: user.signInUserSession.idToken.jwtToken
        }
      });
      console.log('GOT_GOOGLE_API_KEY', apiKey);
      setGoogleApiKey(apiKey);
    } catch (error) {
      console.log(error);
    }
  }

  async function setAuthListener() {
    Hub.listen('auth', (data) => {
      const event = data.payload.event;
      switch (data.payload.event) {
        case 'signOut':
          console.log('signing out...');
          console.log(event);
          updateFormState(() => ({
            ...formState,
            username: '',
            password: '',
            email: '',
            authenticatedUser: null
          }));
          break;
        default:
          break;
      }
    });
  }

Aber ich bekomme den Fehler:

USER_USER_USER null
App.js:78 TypeError: Cannot read property 'signInUserSession' of null
    at getGoogleApiKey (App.js:72)
    at updateAuth (App.js:42)

Wenn dies das falsche Paradigma ist, würde ich mich über Alternativen freuen!

Antworten

4 Yuan-HaoChiang Oct 04 2020 at 08:33

Beim setUserAufruf enthält die userVariable immer noch alte userInformationen ( nullin diesem Fall), unabhängig von async/await:

await checkUser();        // setUser(something) will not happen until next run
await getGoogleApiKey();  // user is still null
await setAuthListener();

Eine andere Möglichkeit wäre, bei userÄnderungen einen weiteren Effekt hinzuzufügen :

useEffect(() => {
  if (user) {
     getGoogleApiKey();
  }
}, [user]);

Oder rufen Sie getGoogleApiKeymit dem Parameter auf:

const user = await checkUser(); // return user
await getGoogleApiKey(user);
await setAuthListener();

Da die Logik komplex wird, würde ich empfehlen, den useReducer-Hook zu verwenden, da der Versand diese komplexen Hin- und Her-Szenarien vereinfacht.