反应功能组件获取数据时 setHooks 的奇怪行为

react functional component Strange behavior of setHooks when I fetch data

我有一个 React class 完成了我需要的工作,我不得不将它更改为功能组件以使用 useLocation()。

事实证明,通过切换到功能组件,我的状态更新不再正常工作。

我的函数是这样的形式

import * as React from "react";
import { useEffect, useState } from "react";
import Axios from "axios";
import { useLocation } from "react-router-dom";

const URL = `my-path`; 

const Sessions: React.FC<{ loadingParam?: boolean | undefined, someBooleanParam?: boolean | undefined, data?: AnyType[] | undefined }> = ({ loadingParam = true, someBooleanParam = undefined, data = undefined}) => {
                        
    const [loading, setLoading] = useState(loadingParam);
    const [someBoolean, setSomeBoolean] = useState(someBooleanParam);
    const [dataFetch, setDataFetch] = useState(data);

    const location:any = useLocation();

    useEffect(() => 
        {
            if(location.state == null){
                console.log("first implementation");
            } else {
                const dataToFill:AnyType[]|undefined = location.state.data;
                if( data ) {
                    setDataFetch(dataToFill);
                    setLoading(false);
                    setSomeBoolean(undefined);
                }
            }
        }
        ,
        [setDataFetch, setLoading, setSomeBoolean]
    );

    async function fetchData() {
        try {
            setLoading(true);
            await Axios.get<AnyType[]>(URL)
                .then(res => {
                    if (res.status === 200 && res != null) {
                        console.log("1 ", dataFetch); //undefined
                        console.log("1 bis ", res.data); //the data I want in the form I want
                        var copy:AnyType[] = [...res.data];

                        setDataFetch([...res.data]);

                        console.log("2 ", dataFetch); //undefined
                        console.log("2 ter ", copy);  //the data I want in the form I want

                        setDataFetch(copy);
                        console.log("2 ", dataFetch); //undefined

                        setLoading(false);

                        if (dataFetch?.length === parseInt(someValue)){
                            setSomeBoolean(true);
                        } else {
                            setSomeBoolean(false);
                        }
                    } else {
                        console.log('problem when fetching the data from backend');
                    }
                })
                .catch(error => {
                    console.log(error);
                });
        } 
        catch (exception) {
          console.log(exception);
        }
    }

    console.log("8 ", dataFetch); //Appears in the web console several times during the execution of the fetchData function with the data I want 

    return(
        <div className="container">
            <div>
                <button onClick={fetchData}> Click to get data </button>
            </div>
            {(someBoolean == true && loading == false) ? 
                Some Action
                : <></>
        </div>
    );
}

export default Sessions;

在这段代码中,在 fetchData 函数中,我需要知道 dataFetch 数组的大小来设置 someBoolean 的值,但是在 运行 时,try 块中没有定义 dataFetch。但是当我在同一个函数中创建一个副本时,它定义得很好,我不明白。

我还尝试将对 Axios 的调用放入返回承诺的异步函数中,从而从我的 fetchData 函数中获取它,但它给了我类似的结果。

我还尝试在没有 try/catch 块的情况下使 fetchData 函数成为非异步的,但结果仍然相同。

我需要的是在 fetchData 函数中,在 .then 块中,流程停止填充我的 dataFetch,然后检查数组的大小,然后呈现我的组件。但我不想设置 setTimeout,因为我认为这是一种过于静态的行为。还有其他方法吗?

有没有人看到我在解释此行为的代码中做错了什么?

提前感谢任何愿意花时间帮助我的人

一种方法是将 setSomeBoolean 部分放入另一个 useEffect 中,该部分在 dataFetch 更改时运行。类似的东西:

import * as React from "react";
import { useEffect, useState } from "react";
import Axios from "axios";
import { useLocation } from "react-router-dom";

const URL = `my-path`; 

const Sessions: React.FC<{ loadingParam?: boolean | undefined, someBooleanParam?: boolean | undefined, data?: AnyType[] | undefined }> = ({ loadingParam = true, someBooleanParam = undefined, data = undefined}) => {
                        
    const [loading, setLoading] = useState(loadingParam);
    const [someBoolean, setSomeBoolean] = useState(someBooleanParam);
    const [dataFetch, setDataFetch] = useState(data);

    const location:any = useLocation();

    useEffect(() => 
        {
            if(location.state == null){
                console.log("first implementation");
            } else {
                const dataToFill:AnyType[]|undefined = location.state.data;
                if( data ) {
                    setDataFetch(dataToFill);
                    setLoading(false);
                    setSomeBoolean(undefined);
                }
            }
        }
        ,
        [setDataFetch, setLoading, setSomeBoolean]
    );

    useEffect(()=>{
        if (dataFetch?.length === parseInt(someValue)){
            setSomeBoolean(true);
        } else {
            setSomeBoolean(false);
        }
        setLoading(false);
    },[dataFetch])


    async function fetchData() {
        try {
            setLoading(true);
            await Axios.get<AnyType[]>(URL)
                .then(res => {
                    if (res.status === 200 && res != null) {
                        console.log("1 ", dataFetch); //undefined
                        console.log("1 bis ", res.data); //the data I want in the form I want
                        var copy:AnyType[] = [...res.data];

                        setDataFetch([...res.data]);

                        console.log("2 ", dataFetch); //undefined
                        console.log("2 ter ", copy);  //the data I want in the form I want

                        setDataFetch(copy);
                        console.log("2 ", dataFetch); //undefined


                    } else {
                        console.log('problem when fetching the data from backend');
                    }
                })
                .catch(error => {
                    console.log(error);
                });
        } 
        catch (exception) {
          console.log(exception);
        }
    }

    console.log("8 ", dataFetch); //Appears in the web console several times during the execution of the fetchData function with the data I want 

    return(
        <div className="container">
            <div>
                <button onClick={fetchData}> Click to get data </button>
            </div>
            {(someBoolean == true && loading == false) ? 
                Some Action
                : <></>
        </div>
    );
}

export default Sessions;

我也不确定你为什么要 [setDataFetch, setLoading, setSomeBoolean] 作为第一个 useEffect 的依赖数组?