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

React应用读取substring时出现Undefined错误求助

解决React中TypeError: Cannot read properties of undefined (reading 'substring')问题

问题描述

在React(Next.js)应用中出现错误:TypeError: Cannot read properties of undefined (reading 'substring'),仅注释掉包含data.created_at.substring的<span>标签时应用可正常运行。尝试使用data ? data.created_at.substring(8,10) : ""的条件渲染方式后,该<span>行显示空白。

相关代码如下:

页面组件

const DocumentationDetail = () => {
    const router = useRouter();
    const { user } = useAuth();
    const id = router.asPath.substring(1);
    const { data } = useDocumentationGet(parseInt(id));

    return (
        <>
            <Head>
                <title>{ data.title }</title>
            </Head>
            <main>
                <MainLayout>
                    <div className={styles.container}>
                        <h1 className={styles.title}>{ data.title }</h1>
                        <span className={styles.info}>Publicado { data.created_at.substring(8, 10) }/{ data.created_at.substring(5, 7) }/{ data.created_at.substring(0, 4) } por { data.author.name }</span>
                        <p className={styles.content}>{ data.content }</p>
                    </div>

                </MainLayout>
            </main>
        </>
    );
}

自定义Hook

export function useDocumentationGet(id) {
    const [data, setData] = useState([]);

    useEffect(() => {
        getDocumentationRequest(id)
            .then(res => {
                setData(res.data);
            })
    }, [])

    return { data };
}

API请求函数

export async function getDocumentationRequest(id) {
  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_API_URL}/documentation/${id}`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },
      },
    );

    if (response.ok) {
      return { data: await response.json() };
    }

    return {
      status: false,
    };
  } catch (err) {
    return {
      status: false,
    };
  }
}

原因分析

  1. 初始状态类型不匹配:自定义Hook中useState([])将初始data设为数组,但API返回的是单个文档对象。初始状态下data是数组,data.created_at必然为undefined,调用substring直接触发报错。
  2. 条件渲染逻辑不严谨:data ? ... : ""中,初始data是数组(布尔值为true),仍会尝试访问data.created_at导致报错;若API请求失败,res.data不存在,data被设为undefined,此时条件渲染返回空字符串,导致<span>空白。
  3. 未处理异步加载状态:API请求是异步操作,组件初始渲染时data还未获取到,直接访问其属性会触发错误。

解决方案

1. 修正初始状态并添加状态管理

将自定义Hook的初始data改为null(符合单对象返回类型),同时添加加载、错误状态,处理请求全生命周期:

export function useDocumentationGet(id) {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);

    useEffect(() => {
        getDocumentationRequest(id)
            .then(res => {
                setData(res.data);
                setError(!res.status);
            })
            .catch(() => setError(true))
            .finally(() => setLoading(false));
    }, [id])

    return { data, loading, error };
}

2. 完善组件的条件渲染与安全访问

在页面组件中先处理加载、错误状态,使用可选链?.安全访问嵌套属性,同时提取日期格式化逻辑:

const DocumentationDetail = () => {
    const router = useRouter();
    const { user } = useAuth();
    const id = router.asPath.substring(1);
    const { data, loading, error } = useDocumentationGet(parseInt(id));

    if (loading) return <div>Cargando...</div>;
    if (error || !data) return <div>Error al cargar la documentación</div>;

    const formatDate = (dateStr) => {
        if (!dateStr) return "";
        return `${dateStr.substring(8, 10)}/${dateStr.substring(5, 7)}/${dateStr.substring(0, 4)}`;
    };

    return (
        <>
            <Head>
                <title>{data.title}</title>
            </Head>
            <main>
                <MainLayout>
                    <div className={styles.container}>
                        <h1 className={styles.title}>{data.title}</h1>
                        <span className={styles.info}>
                            Publicado {formatDate(data.created_at)} por {data.author?.name || "Desconocido"}
                        </span>
                        <p className={styles.content}>{data.content}</p>
                    </div>
                </MainLayout>
            </main>
        </>
    );
}

3. 优化API请求返回逻辑

确保请求失败时明确返回data: undefined,避免后续处理混乱:

export async function getDocumentationRequest(id) {
  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_API_URL}/documentation/${id}`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },
      },
    );

    if (response.ok) {
      return { data: await response.json(), status: true };
    }

    return { status: false, data: undefined };
  } catch (err) {
    return { status: false, data: undefined };
  }
}

关键要点

  • 初始状态必须与API返回的数据类型匹配,避免数组/对象混淆导致的属性访问错误。
  • 必须处理异步请求的加载、成功、失败三种状态,既提升用户体验又避免报错。
  • 使用可选链?.和空值合并||可以更安全地访问嵌套属性,减少冗余的条件判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:13:19