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

React Router中useLoaderData()的类型声明方式与位置

React Router useLoaderData() 类型声明正确方案

问题说明

使用React Router的useLoaderData()钩子从接口获取数据时,接口返回包含tokens数组的对象,需要为返回值声明正确的TypeScript类型,解决映射数据时的类型报错问题。

接口返回结构

{
  "tokens": [
    {
      "id": 1,
      "name": "uniswap",
      "ticker": "UNI",
      "description": "This is the description for Uniswap token"
    },
    {
      "id": 2,
      "name": "balancer",
      "ticker": "BAL",
      "description": "This is the description for Balancer token"
    }
  ]
}

用户现有代码片段

import { NavLink, Link, Outlet, useLoaderData } from 'react-router-dom'

type Token = {
  id: number
  name: string
  ticker: string
  description: string
}

const Tokens = () => { 
  const tokens = useLoaderData()

  return ( 
    <div>
      <div>
        {tokens.map((token: Token) => (
          <Link to='/' key={token.id}>
            <p>{token.name}</p>
            <p>{token.ticker}</p>
            <p>{token.description}</p>
          </Link>
        ))}
      </div>
      <nav>
        <NavLink to='uniswap'>Uniswap</NavLink>
        <NavLink to='balancer'>Balancer</NavLink>
      </nav>
      <Outlet />
    </div>
  );
}

export const tokensLoader = async () => {
  const res = await fetch('http://localhost:4000/tokens')
  return res.json()
}
 
export default Tokens;

用户尝试的两种写法:
写法一:

const tokens: Token[] = useLoaderData()

写法二:

type TokenData = {
  tokens: Token[]
}
const tokens: TokenData = useLoaderData()

正确解法

1. 定义匹配接口的完整类型

首先声明与接口返回结构完全对应的类型:

type Token = {
  id: number
  name: string
  ticker: string
  description: string
}

// 匹配接口返回的顶层结构
type TokenResponse = {
  tokens: Token[]
}

2. 为useLoaderData指定泛型(核心)

useLoaderData()支持泛型参数,直接传入TokenResponse,让TypeScript自动推断返回值类型,无需手动断言:

const Tokens = () => { 
  // 用泛型明确返回值类型
  const responseData = useLoaderData<TokenResponse>()

  return ( 
    <div>
      <div>
        {/* 取出responseData.tokens进行映射,类型完全匹配 */}
        {responseData.tokens.map((token) => (
          <Link to='/' key={token.id}>
            <p>{token.name}</p>
            <p>{token.ticker}</p>
            <p>{token.description}</p>
          </Link>
        ))}
      </div>
      <nav>
        <NavLink to='uniswap'>Uniswap</NavLink>
        <NavLink to='balancer'>Balancer</NavLink>
      </nav>
      <Outlet />
    </div>
  );
}

3. 优化Loader函数的类型(可选但推荐)

为Loader函数指定返回值类型,提升代码严谨性:

export const tokensLoader = async (): Promise<TokenResponse> => {
  const res = await fetch('http://localhost:4000/tokens')
  
  // 新增响应校验,避免错误数据流入组件
  if (!res.ok) {
    throw new Error(`Fetch failed: ${res.statusText}`)
  }

  // 明确res.json()的返回类型
  return res.json() as Promise<TokenResponse>
}

两种尝试写法的问题分析

  • 写法一:错误地将useLoaderData()返回值声明为Token[],但接口返回的是包含tokens数组的对象,并非数组本身,导致后续map调用时类型不匹配。
  • 写法二:类型定义是正确的,但后续代码直接调用tokens.map(),而实际应该调用tokens.tokens.map(),属于逻辑错误而非类型定义错误。

额外建议

  • 始终为useLoaderData()添加泛型参数,这是React Router官方推荐的TypeScript用法,能避免any类型带来的隐患。
  • 在Loader函数中添加响应状态校验,提前处理请求失败的情况,避免错误数据进入组件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 08:12:56