1
votes

I have a conditional rendering while fetching user location using React Native and Expo. I am changing my state once the button is clicked to show spinner, however for some reason my state variable is always false. I understand useEffect hook however I don't think I need to change the variable on any particular lifecycle. Is this the right reasoning? At first I thought it was due to the async nature of the function however it does not seem likely.

State Init

const [loading, toggleLoading] = useState(false);

Code for onClick

{props.location === null ? (
        <Button onPress={getLocationAsync} mode="contained">
          Get Location
        </Button>
      ) : loading === true ? (
        <Button mode="contained">
          <ActivityIndicator />
        </Button>
      ) : (
        <Button mode="outlined">Received</Button>
      )}

Code for getLocationAsync

const getLocationAsync = async () => {
    toggleLoading(true);
    let { status } = await Permissions.askAsync(Permissions.LOCATION);

    if (status !== "granted") { }

    let location = await Location.getCurrentPositionAsync();
    toggleLoading(false);
  };

Logging state anywhere always yields loading as false. Do I actually require something like useEffect in this case?

3

3 Answers

2
votes

Setting a state in React is asynchronous! That's why your logs shows false.

const onPress = () => toggleLoading(true)

useEffect(() => {
  const getLocationAsync = async () => {
    // your actions here
    toggleLoading(false)
  }
  if (loading) getLocationAsync()
}, [loading])

// in your render
<Button {...{ onPress}} mode="contained">Get Location</Button>

If you do like this, you are 100% sure that you getLocationAsync() code is executed only when loading === true!

1
votes

Are you sure it doesn't work? State in React is asynchronous too so your console.log() might not be accurate.

I've created simple example with your code and it works well. Only thing which might be different is your ternary condition. You can't see 'loading' because your first condition is location === null which is null even while loading. I've just modified your first condition like this: location === null && loading !== true and works fine.

0
votes

Can you try

onPress={() => {
   toggleLoading(true);
   getLocationAsync();
}}