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
相关产品推荐
相关产品推荐

