Home > front end >  get value from async function in useState
get value from async function in useState

Time:10-04

I'm using async storage to retrieve my data but how do I use it with useState()?

Example:

async function getdata(){
let d= await AsyncStorage.getItem('Name');
return d;
}

export default function App() {
 const [name, setName] = useState(() => getdata());
 return (<View>...</View>)
}

but this doesn't work since getdata() is async, so how do I solve this problem?

Edit:

I forgot to mention I tried the useEffect() Hook like this:

async function getdata(){
let d= await AsyncStorage.getItem('Name');
console.log('retrieved Data!');
return d;
}

const [name, setName] = useState(()=>0);
  useEffect(() => {
    getData().then(setName(value));
    console.log('moving on...');
  }, []);

but the order of execution was:

'Moving on...'
'retrieved Data!'

where as it should have been the other way around

CodePudding user response:

You'll initialize your state to some empty value. Maybe an empty string, maybe a null. If you like, you can have your component render something different during this time, such as a loading indicator. Then once the data loads, you can set state to render again.

export default function App() {
  const [name, setName] = useState(null);
  useEffect(() => {
    getData().then(value => setName(value));
  }, []);

  if (name === null) {
    return <Text>Loading...</Text>
  } else {
    return (<View>...</View>)
  }
}

CodePudding user response:

You have to use useEffect

export default function App() {
  const [name, setName] = useState('');

  useEffect(() => {
    const bootstrap = async () => {
      const name = await getdata();
      setName(name);
    };
    bootstrap();
  }, []);
  return <View>...</View>;
}

CodePudding user response:

I think the best solution here is to initialize name as false, and then use 'setName' in a .then() callback. setName (and those setter functions that come out of useState generally) is meant to be a way of updating that value asynchronously.

I'm setting name to the boolean 'false' here and checking it strictly. If there is a case where that name field is empty it can just be set to an empty string without causing an infinite loop.

async function getdata(){
let d= await AsyncStorage.getItem('Name');
return d;
}

export default function App() {
 const [name, setName] = useState(false);

 useEffect(() => {
  if (name === false) {
   getData().then((name) => {
    setName(name);
   });
  }
 }, []);
 
 return (<View>...</View>)
}

Keep in mind that your view has to be able to deal with a false name value. How it does that is up to you.

^^^The above solution should effectively solve your problem but I'll make a quick note here: If your component is relatively complex it might be re-rendering a number of times for other reasons and will consequently run the if(name === false) condition as it waits for the callback to resolve. This won't break things but it'll hammer async storage more than necessary and might affect performance. If you find that to be the case, look into 'debouncing' callbacks using the helpful article below. https://medium.com/@gabrielmickey28/using-debounce-with-react-components-f988c28f52c1

  • Related