skip to Main Content

export default function Weather({destiny}) {

const [location, setLocation] = useState('')
const [dataExt, setDataExt] = useState({})

const url_ext = `https://api.openweathermap.org/data/2.5/forecast?q=${destiny}&units=metric&appid="here goes appi id"`

var list = []

const weatherExt = () => {
        axios.get(url_ext).then((responseExt) => {
            setDataExt(responseExt.dataExt)

            list = responseExt.data.list

            
        })
        setLocation('')
}

The idea is that when I want to render the result inside a {variable ? ()=>weatherExt() : null}, this function return an html component with results, but I have the following error using the code above: "Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it."
How can I do to best render results returning an html element with a list without having de error render.
Thanks in advance.

2

Answers


  1. I’m assuming you are calling this function directly in the body of your function.

    Remember that when you call setFunction from useState (in your case it is the "setLocation" function) your component will be rerender.

    See, when you rerender the component, it again creates your function and the function body, in your case -> the weatherExt() function, and this function again causes the component to be rerender.

    React say that you are calling the function that caused the re-render and the re-render calls your function again.

    Your solution is the useEffect hook.

    Try this

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

    And your component should look like this

    const [location, setLocation] = useState('')
    const [dataExt, setDataExt] = useState({})
    const [list, setList] = useState([]);
    
    const url_ext = `https://api.openweathermap.org/data/2.5/forecast?q=${destiny}&units=metric&appid="here goes appi id"`
    
    const weatherExt = () => {
            axios.get(url_ext).then((responseExt) => {
                setDataExt(responseExt.dataExt);
    
                if (responseExt.data.list) {
                  setList(responseExt.data.list);
                } else {
                  setList(null);
                }
            })
            setLocation('');
    }
    
    useEffect(() => {
      weatherExt();
    }, [])
    Login or Signup to reply.
  2. You could do something like this to get an optimized output:

    const [location, setLocation] = useState('')
    const [dataExt, setDataExt] = useState(null)
    const [list, setList] = useState([])
    
    const url_ext = `https://api.openweathermap.org/data/2.5/forecast?q=${destiny}&units=metric&appid="here goes api id"`
    
    const weatherExt = () => {
            axios.get(url_ext).then((responseExt) => {
                setDataExt(responseExt.dataExt || null)
                setList(responseExt.data.list || [])
            })
            setLocation('')
    }
    
    React.useEffect(()=>{
      weatherExt()
    }, [])
    

    Important things to note here:

    1. Doing list = responseExt.data.list should be avoided. Instead use a separate state for that, i.e. use const [list, setList] = useState([]) and then update this state with setList() inside your weatherExt function.
    2. Call the weatherExt function inside useEffect hook such that it will get executed only once after the component has mounted, that is:
    React.useEffect(()=>{
      weatherExt()
    }, [])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search