Mettere le funzioni Async in useEffect () hook in React

Oct 04 2020

Sto finendo un'app in cui desidero nascondere la mia chiave API di GoogleMap dietro la mia API sicura. La mia intenzione è richiedere la chiave API una volta verificato di avere un utente autenticato. Il problema è che tra le chiamate asincrone, le modifiche non si riflettono con il cambio di stato.

Questo è quello che sto facendo:

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;
      }
    });
  }

Ma ricevo l'errore:

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

Se questo è il paradigma sbagliato, apprezzerei qualsiasi alternativa!

Risposte

4 Yuan-HaoChiang Oct 04 2020 at 08:33

Quando setUserviene chiamata, la uservariabile conserva ancora le vecchie userinformazioni ( nullin questo caso), indipendentemente da async/await:

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

Un'altra scelta sarebbe quella di aggiungere un altro effetto quando usercambia:

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

Oppure chiama getGoogleApiKeycon il parametro:

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

Poiché la logica diventa complessa, suggerirei di provare l' hook useReducer perché l'invio semplifica questi scenari complessi avanti e indietro.