You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义手动触发请求Hook返回数据为undefined如何解决

问题原因
  • 异步执行顺序问题:fetchAppList是异步函数,useEffect中调用fetchData()后会立刻执行后续的console.log,此时请求还未返回,state也未触发更新,你拿到的永远是当前渲染闭包里的初始state值。
  • React state更新的快照特性:每次渲染的state都是独立的快照,就算后续请求完成更新了state,也只会触发组件重新渲染,本次渲染作用域里的data和status永远是初始值,不会跟着更新。
代码调整方案

1. 自定义Hook优化

原Hook存在三个问题:不需要暴露内部状态修改方法setStatus给外部、错误场景未更新状态、参数变化时请求配置不会同步更新,修改后代码如下:

import React, { useState, useMemo, useCallback } from "react";
import { AppListResponse } from "../../typings/AppListResponse";

const useFetchAppList = (
    userId: string,
    authToken: string
): [() => Promise<void>, string, AppListResponse | null | undefined] => {
    const [status, setStatus] = useState<string>("idle");
    const [responseData, setData] = useState<AppListResponse | null>();

    // 参数变化时自动更新请求配置
    const options = useMemo(() => ({
        method: "GET",
        headers: {
            CustomAuthToken: authToken,
            UserID: userId,
            Accept: "application/json",
            "Content-Type": "application/json"
        }
    }), [userId, authToken]);

    // 用useCallback稳定函数引用,避免不必要的重渲染
    const fetchAppList = useCallback(async (): Promise<void> => {
        setStatus("fetching");
        let unmounted = false;
        try {
            const response = await fetch(`https://my-endpoint.com/lets-fetch-this`, options);
            const json = await response.json();
            if (!unmounted) {
                setData(json);
                setStatus("successful");
            }
        } catch (error) {
            console.log("error", error);
            if (!unmounted) {
                setStatus("error");
            }
        }
        // 组件卸载时取消state更新,避免内存泄漏警告
        return () => {
            unmounted = true;
        }
    }, [options]);

    // 去掉暴露的setStatus,避免外部随意修改内部状态
    return [fetchAppList, status, responseData];
};

export default useFetchAppList;

2. 组件调用逻辑调整

如果需要观测请求后的最新状态,单独添加监听data和status的副作用即可:

const [fetchAppList, status, data] = useFetchAppList(userId, authToken);

// 挂载时触发请求
useEffect(() => {
    fetchAppList();
}, [fetchAppList]);

// 监听状态变化,拿到更新后的值
useEffect(() => {
    console.log(data, status);
}, [data, status]);

// 随时触发请求示例:比如绑定到按钮点击事件
const handleRefresh = () => {
    fetchAppList();
};
效果验证

调整后组件挂载会自动触发请求,你也可以在任意业务场景(比如按钮点击、下拉刷新)直接调用fetchAppList触发请求,status会依次变为fetching、successful/error,data会同步更新为接口返回值。

内容的提问来源于stack exchange,提问作者erol_smsr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 10:36:01