DEV Community

mitchelln11
mitchelln11

Posted on

Run Function after useEffect to Manipulate Data?

I'm using the OpenWeather REST API which comes in JSON format. I know I have to make my fetch,(Axios in my case) call inside the useEffect because the component needs to render first, then calls the REST endpoint.

I can log out the information, only the temperature comes in Kelvin. In this case, I need to create another function that does the conversion. The only thing I am stuck on is how to transfer the API object info to my temperature conversion function. Any thoughts on how to do this? I assume props are involved.

My Code:

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import {KelvinConvert} from './MathConversions';

const LocalWeather = () => {
    const [openWeather, setWeather] = useState({});

    useEffect(() => {
        axiosGet();
    }, []); //  Run once on load

    const axiosGet = () => {
        axios.get(`https://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=${process.env.REACT_APP_WEATHER_KEY}`)
        .then(data => setWeather(data.data));
    }

    return (
        <ul id="weather-container">
            <KelvinConvert />  // Trying to add converted temperature here
            <li>{openWeather.main && openWeather.main.temp}&deg;F</li>
            <li>{openWeather.weather && openWeather.weather[0].main}</li>
            <li>{openWeather.name}</li>
        </ul>
    );
}

export default LocalWeather;

Then there's my method to do the conversion.

import React, {useState, useEffect} from 'react';

export const KelvinConvert = props => {
  const [temperature, setTemperature] = useState({props});

  useEffect(() => {
    convertKelvinToFahrenheit();
  }, []);

  const convertKelvinToFahrenheit = props => {
    setTemperature(((props - 273.15) * 9/5) + 32);
  }

  return {temperature};

}

Not actually properly passing data to the convertKelvinToFahrenheit method.

Getting the following errors:

./src/components/MathConversions.js
  Line 1:8: 'React' is defined but never used
no-unused-vars
  Line 4:10: 'temperature' is assigned a value but never used                                                     
no-unused-vars
Compiled with warnings.

Not sure where to go from this point.

Discussion (11)

Collapse
taylorbeeston profile image
Taylor Beeston

Hi Mitchell, is there any reason why you can't inline

const convertKelvinToFahrenheit = kelvin =>
  (kelvin - 273.15) * 9/5 + 32;

into your LocalWeather component and then simply change axiosGet to

const axiosGet = () => {
        axios.get(`https://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=${process.env.REACT_APP_WEATHER_KEY}`)
        .then(data => setWeather(convertKelvinToFahrenheit(data.data)));
    }
Collapse
mitchelln11 profile image
mitchelln11 Author

U talking about just moving the inline function to the LocalWeather component, then just running it like your last block of code?

I just tried that, and I'm getting the following error:
Line 11:8: React Hook useEffect has a missing dependency: 'axiosGet'. Either include it or remove the dependency array react-hooks/exhaustive-deps

Collapse
taylorbeeston profile image
Taylor Beeston

I am so sorry, I just realized what you are trying to accomplish. I misunderstood your problem.

As was said before me, you need your KelvinConvert component to return valid JSX in order to be rendered. This can be done by changing its definition to be something like this:

import React from 'react';

const KelvinConvert = ({ kelvin }) => {
  const kToF = k => (k - 273.15) * 9/5 + 32;

  return <li>{kToF(kelvin)}</li>;
};

export default KelvinConvert;

And then passing your Kelvin temperature to it by changing

<KelvinConvert />  // Trying to add converted temperature here

To

<KelvinConvert kelvin={openWeather.kelvin} />

When the useEffect hook finishes, it will update the prop sent to your component.

Please note, I don't actually know what the openWeather object will look like since I haven't used that API, nor do I know specifically what you're trying to get from it, so it is very likely that using openWeather.kelvin like I wrote above will not work. Please replace that with the data you want your KelvinConvert component to convert.

Also, I wrote all of this on my phone, so please forgive any typos or bad code

Thread Thread
mitchelln11 profile image
mitchelln11 Author

Sweet, getting 57.938000000000045, so I just need to get that, but that did the trick. Thank you so much.

As far as the object goes with REACT, it's weird, should be openWeather.main.temp, but that comes back undefined. Instead, you have to add it as

openWeather.main && openWeather.main.temp
Thread Thread
taylorbeeston profile image
Taylor Beeston

Weird. That's likely because openWeather is an empty object until the API call finishes. You might be able to use the new optional chaining operator to get past that! Try

openWeather?.main?.temp

And see if that works!

As for the float formatting, use the good ol' toFixed method like so

kToF(kelvin).toFixed(2)
Thread Thread
mitchelln11 profile image
mitchelln11 Author

57.15, perfect.
I also had no idea about the optional chaining thing. Good to know thanks. That part looks like it's working as well.

openWeather?.main?.temp
AND
openWeather?.weather?.[0].main --- returns cloud/rain/etc.

You know your stuff. It's much appreciated!

Thread Thread
anfo000 profile image
anfo000

Wow.. I didnt know about the chaining operator.
Thanks

Thread Thread
taylorbeeston profile image
Taylor Beeston • Edited

No problem guys! Happy to help.

About optional chaining, it's extremely new, as in I think it just became official standardized this year, so please make sure you're running any code that uses it through babel (if you used create-react-app it should be doing this already) because browser support is going to be terrible

Collapse
muni profile image
Muni Perez

You can do everything in the effect function:

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import {KelvinConvert} from './MathConversions';

const LocalWeather = () => {
    const [openWeather, setWeather] = useState({});

    useEffect(() => {
        axios.get(`https://api.openweathermap.org/data/2.5/weather? 
        q=London,uk&APPID=${process.env.REACT_APP_WEATHER_KEY}`)
        .then(data => {
            setWeather( KelvinConvert(data.data));
         });
    }, []); //  Run once on load

    return (
        <ul id="weather-container">
            <KelvinConvert />  // Trying to add converted temperature here
            <li>{openWeather.main && openWeather.main.temp}&deg;F</li>
            <li>{openWeather.weather && openWeather.weather[0].main}</li>
            <li>{openWeather.name}</li>
        </ul>
    );
}

export default LocalWeather;

If you get this error:

Line 11:8: React Hook useEffect has a missing dependency: 'KelvinConvert'. Either include it or remove the dependency array react-hooks/exhaustive-deps

You can safely ignore it because since your Effect runs only once, you don't need to keep track of the dependency.

Collapse
anfo000 profile image
anfo000

Hi Mitchell... The kevin convert is not returning any jsx... That's why you are getting that error..

If you want to convert and show the farenheit maybe return some

{temperature}

.

Also you are not passing any prop to the kelvinconvert component.

Collapse
mitchelln11 profile image
mitchelln11 Author

So the following doesn't return anything?

return {temperature};

Also, how do you pass info to the props from 1 component to another after the initial fetch/axios call?