Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using useEffect in combination with Axios fetching API data returns null - how to deal with this?

Tags:

reactjs

Fetching data using Axios and useEffect results in null before the actual object is loaded.

Unfortunately, I am not able to use object destructuring before the actual object is not empty.

I am forced to use a hook to check whether an object is empty or not.

For instance, I would like to create multiple functions and split my code up in separate functions for better readability.

This is my HTTP request Hook:

import { useState, useEffect } from 'react';

import axios from 'axios';

export const useHttp = (url, dependencies) => {
    const [isLoading, setIsLoading] = useState(false);
    const [fetchedData, setFetchedData] = useState(null);

    useEffect(() => {
        setIsLoading(true);

        axios
            .get(url)
            .then(response => {
                setIsLoading(false);
                setFetchedData(response.data);
            })
            .catch(error => {
                console.error('Oops!', error);
                setIsLoading(false);
            });
    }, dependencies);

    return [isLoading, fetchedData];
};

Followed by my page component:

import React from 'react';

import { PAGE_ABOUT, API_URL } from 'constants/import';

import Header from './sections/Header';
import Main from './sections/Main';
import Aside from './sections/Aside';

import { useHttp } from 'hooks/http';

const About = () => {
    const [isLoading, about] = useHttp(PAGE_ABOUT, []);

    if (!isLoading && about) {
        return (
            <section className="about">
                <div className="row">
                    <Header
                        featuredImage={API_URL + about.page_featured_image.path}
                        authorImage={API_URL + about.page_author_image.path}
                        authorImageMeta={about.page_author_image.meta.title}
                        title={about.about_title}
                        subtitle={about.about_subtitle}
                    />

                    <Main
                        title={about.page_title}
                        content={about.page_content}
                    />

                    <Aside
                        title={about.about_title}
                        content={about.about_content}
                    />
                </div>
            </section>
        );
    }
};

export default React.memo(About);

The actual problem I am not able to nest functions before the object is actually returned.

Is there a way to fetch data without a check by any chance? or a cleaner solution would help.

I would like to use multiple components to split up the code.

Any advice or suggestion would be highly appreciated.

like image 457
Galanthus Avatar asked Jul 09 '19 16:07

Galanthus


People also ask

Can we use Axios in useEffect?

To use Axios with the useEffect hook, we just define an async function and call it inside the useEffect callback. Alternatively, we can use the useAxios hook provided by the axios-hooks library.


1 Answers

What you are asking would be bad for UIs. You don't want to block the UI rendering when you're fetching data. So the common practice is showing a Loading spinner or (if you're counting on the request being fast) just rendering nothing until it pops up.

So you would have something like:

const About = () => {
    const [isLoading, about] = useHttp(PAGE_ABOUT, []);

    if (isLoading) return null; // or <Loading />

    return (
       <section className="about">
            <div className="row">
                <Header
                    featuredImage={API_URL + about.page_featured_image.path}
                    authorImage={API_URL + about.page_author_image.path}
                    authorImageMeta={about.page_author_image.meta.title}
                    title={about.about_title}
                    subtitle={about.about_subtitle}
                />

                <Main
                  title={about.page_title}
                  content={about.page_content}
                />

                <Aside
                  title={about.about_title}
                  content={about.about_content}
                />
            </div>
        </section>
    );
};

If your api has no protection for errors and you're afraid of about being null or undefined you can wrap the component with an Error Boundary Component and show a default error. But that depends if you use those in your app.

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

like image 168
João Cunha Avatar answered Sep 20 '22 17:09

João Cunha