Search code examples
javascripttypescriptasync-awaitexpoasyncstorage

Calling async function returning promise object using typescript on expo


Trying to return different functions (with views) on typescript expo, based on a condition set on activeStorage.

If you look in the code, when showIntro is called, I want to to show the value that's returned from getScreen but instead, when I console log, it's returning a promise object

When I console log await AsyncStorage.getItem('showIntro'); inside getScreen it's giving me the value. Not sure if it's a bug or if there's something wrong with the code?

import AsyncStorage from '@react-native-community/async-storage'

const data = [{...}, {...}, {...}]

const getScreen = async () => {
  return await AsyncStorage.getItem('showIntro'); 
}

function App() {
  const [showIntro, updateShowIntro] = React.useState(getScreen());

  const onDone = () => {
     AsyncStorage.setItem('showIntro', false).then(()=>{});
     updateShowIntro(false);
  }

  return (
  { (showIntro) ? (
      <AppIntroSlider
        renderItem={renderItem}
        data={data}
        onDone={onDone}/>
      ) : (
        <ShowApp />
      )
    }
  );
 }

Solution

  • Your getScreen returns a Promise since you're using async/await. What you need to do is to call getScreen when your component loads for the first time inside of a React.useEffect hook, then update your showIntro state after it resolves with whatever value you're expecting.

    Using an async/await function to "wait" for AsyncStorage.getItem("showIntro") to resolve with some value before returning has really no effect - you are still dealing with a Promise that resolves once the "inner" Promise completes.

    From MDN:

    The return value is a Promise which will be resolved with the value returned by the async function, or rejected with an exception thrown from, or uncaught within, the async function.

    import AsyncStorage from '@react-native-community/async-storage'
    
    const data = [{...}, {...}, {...}]
    
    // no need for `async/await` here, using `async/await`
    // turns your `getScreen` function into a `Promise`, 
    // you get the same exact result, so you might as well 
    // call your `AsyncStorage.getItem("showIntro")` function
    // directly in the `React.useEffect` hook rather than
    // through this `getScreen` function
    const getScreen = () => {
      return AsyncStorage.getItem("showIntro");
    }
    
    function App() {
      const [showIntro, updateShowIntro] = React.useState(null);
    
      React.useEffect(() => {
        getScreen()
          .then(result => {
            updateShowIntro(result);
          });
          .catch(/* handle errors appropriately */);
    
        // alternatively, just call `AsyncStorage.getItem("showIntro")` here
        // AsyncStorage.getItem("showIntro")
        //   .then(result => { updateShowIntro(result); })
        //   .catch(/* handle errors appropriately */);
      }, []);
    
      const onDone = () => {
         // should `updateShowIntro` be inside `then`?
         AsyncStorage.setItem('showIntro', false)
           .then(() => {
             updateShowIntro(false);
           })
           .catch(/* handle errors appropriately */);
      }
    
      return showIntro ? (
        <AppIntroSlider
          renderItem={renderItem}
          data={data}
          onDone={onDone}
        />
      ) : (
        <ShowApp />
      );
     }
    

    References: