Skip to content
Advertisement

How to use an async database call to set a variable with useState() and useEffect()?

I’m trying to set a variable with a simple GET database call. The database call is returning the data correctly, but the variable remains undefined after every re-render. Code is below… the getMyThing() function in the useState() function is working correctly and returning the data I want.

import { getMyThing } from '../../utils/databaseCalls'

const MyComponent: React.FC = () => {
  const { id } = useParams();
  const [myThing, setMyThing] = useState(getMyThing(id));

  useEffect(() => {
    setMyThing(myThing)
  }, [myThing]);
}

My thinking here was to use useState() to set the initial state of the myThing variable with the data returned from my database. I assume it’s not immediately working since a database call is asynchronous, so I thought I could use useEffect() to update the myThing variable after the response of the database call completes, since that would trigger the useEffect() function because I have the myThing variable included as a dependency.

What am I missing here? Thanks!

EDIT: Thanks for the answers everyone, but I still can’t get it to work by calling the getMyThing function asynchronously inside useEffect(). Is something wrong with my database call function? I guess it’s not set up to a return a promise? Here’s what that looks like:

export const getMyThing = (id) => {
    axios.get('http://localhost:4000/thing/' + id)
        .then(response => {
            return(response.data);
        })
        .catch(function (error){
            console.log(error);
        })
}

Advertisement

Answer

You should do all your side effects(fetching data, subscriptions and such) in useEffect hooks and event handlers. Don’t execute async logic in useState as you just assign the promise itself to the variable and not the result of it. In any case, it is a bad practice and it won’t work. You should either:

import { getMyThing } from '../../utils/databaseCalls'

const MyComponent: React.FC = () => {
    const { id } = useParams();

    const [myThing, setMyThing] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            const result = await getMyThing(id);

            setMyThing(result);
        };

        fetchData();
    }, [id, getMyThing]);
}

Or if you don’t want to introduce an async function:

import { getMyThing } from '../../utils/databaseCalls'

const MyComponent: React.FC = () => {
    const { id } = useParams();

    const [myThing, setMyThing] = useState(null);

    useEffect(() => {
        getMyThing()
            .then(result => setMyThing(result));
    }, [id, getMyThing]);
}

Also, take note of the [id, getMyThing] part as it is important. This is a dependency array determining when your useEffect hooks are gonna execute/re-execute.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement