0

I have just started learning react. I have a component which is calling the weather API and fetching data for user provided location, user input is getting updated under userLoc but somehow the state is not getting updated for finalLoc and whenever I console log it, it is showing undefined.

const Inputs = props => {

    const [userLocation, setUserLocation] = React.useState('')


    const [finalLocation, setFinalLocation] = React.useState('')

    function fetchLocation(e) {
        setUserLocation (e.target.value)
    }

    function fetchDetails(e) {
        e.preventDefault()

        let baseURL = '//api.openweathermap.org/data/2.5/weather?q='
        const API_KEY = '&API_KEY'
        let total = baseURL + userLocation + API_KEY
        console.log(userLocation) // Outputs the input value
        setFinalLocation(userLocation)
        console.log(finalLocation) // Comes as blank
        console.log(total);
   
    }
    return (
        <div className='inputs'>
            <p className="label">Enter the location to find the weather.</p>
            <input type="text" className='loc-input' autoFocus placeholder='Enter a location' name="" id="location" onChange={fetchLocation} value={loc.userLoc || ""} />
            <button onClick={fetchDetails}>Get Details</button>
            <Outputs loc={loc.finalLoc} results={loc.result} />
 
        </div>
    )
}
ankitjt
  • 477
  • 1
  • 5
  • 15
  • I believe that the function call for `setLoc` is resetting the entire state and setting up a new one. can you try this `setLoc({...loc, finalLoc: loc.userLoc})` whenever you are calling the function `setLoc` – kunal panchal Feb 18 '21 at 09:48
  • Does this answer your question? [Updating and merging state object using React useState() hook](https://stackoverflow.com/questions/55342406/updating-and-merging-state-object-using-react-usestate-hook) – Anurag Srivastava Feb 18 '21 at 09:50
  • @kunalpanchal I tired doing that , still the finalLoc is coming as undefined, moreover if I console loc it is not populating the object with finalLoc. – ankitjt Feb 18 '21 at 10:05
  • why don't you try creating 3 different just like, `const [finalLoc, setFinalLoc] = React.useState("");` `const [userLoc, setUserLoc] = React.useState("");` `const [data, setData] = React.useState([]);` and use these to manipulate instead of creating single object. check out my below code snippet for example. – kunal panchal Feb 18 '21 at 10:10
  • @kunalpanchal will try that approach, out of curiosity can't it be achieved with defining just one state? – ankitjt Feb 18 '21 at 10:14
  • Why can't it? but this approach is used to simplify the code and calling the methods, user readable and understandable. – kunal panchal Feb 18 '21 at 10:18

3 Answers3

1

const Inputs = props => {
    const [finalLoc, setFinalLoc] = React.useState("");
    const [userLoc, setUserLoc] = React.useState("");
    const [data, setData] = React.useState([]);

    function fetchLocation(e) {
        userLoc(  e.target.value )
    }

    function fetchDetails(e) {
        let baseURL = '//api.openweathermap.org/data/2.5/weather?q='
        let API_KEY = '&appid=API_KEY'
        let total = baseURL + loc.userLoc + API_KEY

        setFinalLoc( userLoc )

        fetch(total)
            .then(response => response.json())
            .then(data => {
                setData(  data )
            })
        }
    return (
        <div className='inputs'>
            <p className="label">Enter the location to find the weather.</p>
            <input type="text" className='loc-input' autoFocus placeholder='Enter a location' name="" id="location" onChange={fetchLocation} value={ userLoc || ""} />
            <button onClick={fetchDetails}>Get Details</button>
            <Outputs loc={ finalLoc} results={data} />
 
        </div>
    )
}
kunal panchal
  • 798
  • 5
  • 21
  • I updated the code in my original question but the finalLocation is still coming as blank when i log it. – ankitjt Feb 19 '21 at 05:16
  • what error do you get on the console? if not then check is the state is getting updated or not?!! as i read your code and as per my understanding you don't need the extra state `setFinalLocation` which is just getting added but never been used so i think you should use the `userLocation` directly for your code. – kunal panchal Feb 19 '21 at 08:15
0

If you update a state when using useState you don't write it as

setState({state: //data})

But

setState(//data)

The updating method in useState is similar to class component setState method but you have to update it differently.

See more about useState here.

If your state is an object you should update it as an object:

  const [state, setState] = useState({
    name: "John",
    lastName: "Due",
  });

  setState({
    name: "Liam",
    lastName: "call",
  });

BTW,

If you are updating multiple values in your state, You should update it in one function.#1

Note: Each time you're updating your state cuase React to re-render and slow your app. For better performance you should always try to re-render your app as less as possible.

Edit:

#1 if your state is an object you should update it in one function.

Uria Levi
  • 258
  • 1
  • 11
  • @Levi, following with what you explained , wouldn't the user input be updated in a separate function since two handlers are in work here? – ankitjt Feb 18 '21 at 10:12
  • You'll have to use multiple states in that case - it's very common to have Function Component with multiple states – Uria Levi Feb 18 '21 at 10:18
0

You can use the functional form. The function will receive the previous value, and return an updated value. so to update the state we have to make copy of previous value with updated one and then set the state with updated values

setLoc((loc) => ({ ...loc, finalLoc: loc.userLoc }));

same when you get result data keep copy of previous state setLoc((loc) => ({ ...loc, result: data }));