0

Working with React Native creating a weather app and when I try to set a variable using useState() and it wont set the first time I load the code, but if I change something then change it back and save, the state will set. The main error is occuring in the generateRandomCity function, list of cities I have locally.

import { View, Text, StyleSheet, SafeAreaView, Image, Linking, ActivityIndicator} from 'react-native'
import React, {useState, useEffect} from 'react'
import {SearchBar} from 'react-native-elements'
import {cities} from '../assets/cities'
import { Button } from 'react-native-elements/dist/buttons/Button'


export default function IntroScreen({navigation}) {
    
    const [isLoading, setLoading] = useState(false);
    const [data, setData] = useState({});
    const [lat, setLat] = useState("");
    const [lng, setLng] = useState("");
    const [randomCity, setRandomCity] = useState("")

    var randCity,randLat,randLng = "";
    const api_key = "XXXXXXXXXXX";



    useEffect(() => {
        const generateRandomCity = () => {
            console.log("-----")
            randCityTotal = cities[Math.floor(Math.random()*cities.length)];
            randCityArray = randCityTotal.split(", ");
            console.log(randCityArray)
            randCity = randCityArray[0]+", "+randCityArray[1];
            setRandomCity(randCity);
            // randLat = randCityArray[2];
            setLat(randCityArray[2]);
            // randLng = randCityArray[3];
            setLng(randCityArray[3]);
            console.log(randCity)
            if (lat != randCityArray[2]){
                setLat(randCityArray[2]);
                console.log(lat,"the")
            } else {
            console.log(lat+", "+randCityArray[2]);
            console.log(lng+", "+randCityArray[3]);
            console.log(data.temp,' rand city button');
            }

        } 
        const getWeather = async () => {
            try {
                console.log(lat," is lat and ",lng);
                const response = (await fetch('https://api.openweathermap.org/data/2.5/weather?units=imperial&lat='+lat+'&lon='+lng+'&appid='+api_key+''));
                const json = (await response.json());
                setData(json.main);
                console.log(data.temp, 'get weather');
            } catch (error) {
                console.error(error);
            } finally {
                setLoading(false);
           }
        }
        generateRandomCity()
        getWeather()
    }, []);




    const [search, setSearch] = useState("");

    const updateSearch = (search) => {
      setSearch(search);
    };

    return (
        <SafeAreaView styles={styles.container}>
            <View style={styles.header}>
                <View style={{flexDirection:'row', alignItems:'flex-end'}}>
                    <Image 
                    source = {require('../assets/sunCloud.png')}
                    />
                    <Text style={{fontWeight:'bold', }}>clouds!</Text>
                </View>
                <View style={{paddingVertical:15}}></View>
                <SearchBar
                style={styles.searchBar}
                placeholder="Enter a city..."
                value={search}
                onChangeText={updateSearch}
                lightTheme
                 />
            </View> 
            <View style={styles.midSection}>
                <Text style={{fontSize: 30}}>{randomCity}</Text>
                <Text>{"" && data.temp}</Text>
                {/* <Text>placeholder</Text> */}
                {/* <Button style={{width:30, height: 30, backgroundColor: '#000', left: 10}} onPress={generateRandomCity}/> */}
            </View>
            <View style={styles.footer}>
                <Text>Created by:xx</Text>
                <Text
                    style={{color:'blue', fontSize:8}}
                    onPress={() => Linking.openURL('https://simplemaps.com/data/us-cities')}
                >
                    [City list obtained from simplemaps.com]
                </Text>
            </View>   
        </SafeAreaView>
  )
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        // padding: 10
    },
    footer: {
        justifyContent: 'flex-end',
        alignItems:'center'
    },  
    header: {
        padding: 10,
    },
    midSection: {
        height: '50%',
        alignItems: 'center',
        justifyContent: 'center',
        borderColor: '#000',
        borderWidth: 1,
    },
    searchBar: {
        backgroundColor: '#fff',
        borderColor: '#000',
        borderWidth: 1,
        borderRadius: 5,
        padding: 5,
    },
})

and the outputs I'm getting after the save method then full refreshing are (dashed lines separate the outputs):

iOS Bundling complete 37ms
iOS Running app on iPhone 13 Pro Max
-----
Array [
  "St. Thomas",
  "North Dakota",
  "48.6192",
  "-97.4471",
]
St. Thomas, North Dakota
 the
  is lat and  
undefined get weather
-----
Array [
  "San Fidel",
  "New Mexico",
  "35.1025",
  "-107.5975",
]
San Fidel, New Mexico
41.0272 the
41.0272  is lat and  -92.8039
81.95 get weather
peeenut
  • 13
  • 4
  • Since `getWeather` depends on `generateRandomCity` setting state, you can't run it in the same loop like you're doing. Create another `useEffect` and run `getWeather` only when `lat` and `lng` change. – jnpdx Apr 06 '22 at 00:34
  • @jnpdx what would be the method to only run when they change? Not very familiar with useEffect() – peeenut Apr 06 '22 at 00:49
  • The second parameter in `useEffect` is an array of dependencies. So, your second `useEffect` would have `[lat,lng, randomCity]` for the second parameter. – jnpdx Apr 06 '22 at 00:50
  • @jnpdx okay I've set it up now, but now the lat and lng aren't rendering the same values: I'm getting a value from another city being set for lat but the array value is the correct lat. any ideas? – peeenut Apr 06 '22 at 02:12
  • @jnpdx looks like it's sort of a console speed thing. The console shows it too quickly but when I render an element on screen the values are correct but the console is wrong. – peeenut Apr 06 '22 at 02:33
  • It's not related to the speed of the console -- it has to do with the fact that `useState` updates state asynchronously. You can't reliably log the value to the console right after setting -- you'd have to put the `console.log` in the `useEffect` as well. Read https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately for more information. – jnpdx Apr 06 '22 at 02:53

0 Answers0