Search code examples
javascriptreactjsaxios

When sending axios requests, the component is rendered too many times (or not)


I use the following code:

The useBaseAxios hook (the basic hook for queries, will be used inside another custom hook)

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

const baseAxios = axios.create({
    baseURL: 'http://127.0.0.1:8000/api/v1',
});

const useBaseAxios = ({ method = "GET", url }) => {
    const [data, setData] = useState(null);
    const [isLoading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const controller = new AbortController();
        const signal = controller.signal;

        const fetchData = async () => {
            try {
                const response = await baseAxios.request({ method, url, signal })
                setData(response.data)

            } catch (error) {
                if (!axios.isCancel(error)){
                    setError(error)
                }
            } finally {
                setLoading(false)
            }
        }

        if (!data) {
            fetchData()
        }

        return () => {
            controller.abort()
        }

    }, [method, url])

    return [data, isLoading, error]
};

export default useBaseAxios;

The useClosestLesson hook (uses useBaseAxios, used in the Main component)

import useBaseAxios from "./useBaseAxios";

function useClosestLessons() {
    const [data, isLoading, error] = useBaseAxios({ method: 'GET', url: '/lessons' })

    let lessonsSchedule = [];
    let currentLesson = {};

    if (data) {
        lessonsSchedule = [...data]
        currentLesson = lessonsSchedule[0]
    }

    return [lessonsSchedule, currentLesson, isLoading, error]
}

export default useClosestLessons

The Main component (when it is rendered, the console logs are displayed)

import React from "react"; 
import './Main.scss';
import useClosestLessons from "../../hooks/fetch-hooks/useClosestLessons";
import { useState, useEffect, useCallback } from "react";
import axios from "axios";

const Main = () => {
    const [lessonsSchedule, currentLessons, isLoading, error] = useClosestLessons();

    console.log(lessonsSchedule)
    console.log(currentLessons)

    if (isLoading) return (<p>Загрузка...</p>)

    return(...)

Without using StrictMode, I expect to receive "null", "null" in the console, then the necessary array and object.

If you return it, I get the following picture:

console.logs

If I look into profiler, there are 3 renders of Main component.

profiler

Should this be the case, and if so, why?

I only expecting for a detailed explanation of this case is sufficient.


Solution

  • React components rerender for one of two reasons:

    1. Their state and/or props update
    2. Their parent component rerendered

    The useBaseAxios state is what appears to be triggering the Main component to rerender.

    I see nothing that would return any null values.

    I also suspect you are actually using the React.StrictMode component, and if so then the logs make sense to me. The StrictMode component double-mounts components and double-invokes their render method and various lifecycle methods/hooks, and you are console logging as an unintentional side-effect directly in the component function body, e.g. its "render method".

    I see 3 discrete "renders" according to your log output:

    1. Two sets of "[]" and "{}" from the initial mounting * **
    2. Another two sets of "[]" and "{}" from the double-mount * **
    3. The final two sets with the computed/populated lessonsSchedule, currentLessons values.

    * See Fixing bugs found by double rendering in development: Some functions are called twice to help detect impure functions, which includes the component function body top-level logic.

    ** See Fixing bugs found by re-running Effects in development React will also run one extra setup + cleanup cycle in development.

    I think this is mostly just a misunderstanding of your logs and what/how they correlate to the React component lifecycle.