skip to Main Content

I have a react app like so:

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

const Body = () => {
    const defaultVersions = [
        {
            version: '2.96.0',
            status: null,
        }
    ];

    const [versions, setVersions] = useState(defaultVersions);

    const getData = version => {
        axios.get(`https://cdn10/${version}/en-US/test.js`)
            .then(response => {
                console.log(response.status);
                return response.status;
            })
            .catch(err => {
                console.log('in here');
            })
    };

    const onClick = () => {
        setVersions(versions.map(item => {
            const { version } = item;
            return { version, status: getData(version) };
        }));
    };

    return (
        <>
            <button onClick={onClick}>Check Versions</button>
            <ul>
                {versions.map(item => {
                    const { version, status } = item;
                    return <li>{`${version}: ${status}`}</li>
                })}
            </ul>
        </>
    );
}

export default Body;

And the console.log in getData works, but when I try to use getData to set the new value in my state on the button click, it’s returning undefined. I’ve tried making getData async/await, but that didn’t work. Any insight is appreciated!

3

Answers


  1. You can use async/await syntax and Promise.all() method.

    For example:

    const getData = async (version) => {
      try {
        const response = await axios.get(
          `https://cdn10/${version}/en-US/test.js`
        );
        return response.status;
      } catch (error) {
        console.log(error);
        return false;
      }
    };
    
    const onClick = async () => {
      const newVersions = await Promise.all(
        versions.map(async (item) => {
          const { version } = item;
          const status = await getData(version);
          return { version, status };
        })
      );
      setVersions(newVersions);
    };
    

    To see the whole example, please see codesandbox.io.

    PS: I forked your codesandbox and fixed errors.

    Login or Signup to reply.
  2. Problem is that your getData is not returning anything, yes you are calling your function but you aren’t returning the promise returned by your axios call. That’s the first problem.
    Second problem is that you are expecting multiple results when you click the button since you are doing a map of versions, in other words it’s not just one promise, there could be many so you need to await all of them before setting the values

    I think it’s cleaner if we write it this way

    const getData = async (version) => {
    try{
      const response = await axios.get(`https://cdn10/${version}/en-US/test.js`)
      return response.status;
    } catch(e){
      console.log("Something went wrong")
      throw new Error(e)
    }
           
    };
    
    const onClick = async () => {
     const myData = await Promise.all(
      versions.map(async (item) => {
          const { version } = item;
          const status = await getData(version)
          return { version, status };
        })
     )
     setVersions(myData)
    }
    

    This function can be improved but for sakes of this example this will work

    Login or Signup to reply.
  3. First of all, you missed return in getData. In JavaScript the result of function that has no return is undefined. So it always returns undefiend.

    When we return axios.get the return type is Promise. So we should use async await or .then. You can update your code like this.

    import React, { useState } from 'react';
    import axios from 'axios';
    
    const defaultVersions = [
        {
            version: '2.96.0',
            status: null,
        }
    ];
    
    const Body = () => {
        const [versions, setVersions] = useState(defaultVersions);
    
        const getData = version => axios.get(`https://cdn10/${version}/en-US/test.js`)
            .then(response => response.status)
            .catch(err => {
                console.log('in here');
            });
    
        const onClick = async () => {
            setVersions(
                await Promise.all(
                    versions.map(async ({ version, status }) => ({
                        version,
                        status: (await getData(version)) ?? status,
                    }))
                )
            );
        };
    
        return (
            <>
                <button onClick={onClick}>Check Versions</button>
                <ul>
                    {versions.map(item => {
                        const { version, status } = item;
                        return <li key={version}>{`${version}: ${status}`}</li>
                    })}
                </ul>
            </>
        );
    }
    
    export default Body;
    

    PS: When rendering list elements, we need to define a key prop.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search