Jotai 2.x中atomsWithQuery返回Promise引发类型错误的解决方法
修复jotai-tanstack-query新版本中atomsWithQuery返回类型导致的TS错误
这个问题是因为jotai-tanstack-query从0.4.x升级到0.7.x后,atomsWithQuery的返回行为发生了变化:新版本默认返回的原子值可能是已解析的数组或Pending状态的Promise,而旧版本会自动处理异步状态直接返回数组类型。针对这个类型不匹配问题,有几种简洁的修复方式:
方案1:使用React Suspense处理异步状态(推荐)
Jotai 2.x和新版jotai-tanstack-query原生支持React Suspense,只需用Suspense包裹使用该原子的组件,useAtomValue就会直接返回已解析的Pokemon[]类型,无需处理Promise:
import { Suspense } from 'react'; import { useAtomValue } from 'jotai'; import { allPokemonAtom } from './your-atom-file'; function PokemonList() { // 当组件在Suspense内时,allPokemon直接是Pokemon[]类型 const allPokemon = useAtomValue(allPokemonAtom); const filteredPokemon = allPokemon.filter(pokemon => pokemon.name.includes('pika')); return ( <ul> {filteredPokemon.map(pokemon => ( <li key={pokemon.id}>{pokemon.name}</li> ))} </ul> ); } // 在父组件中用Suspense包裹 function App() { return ( <Suspense fallback={<div>加载中...</div>}> <PokemonList /> </Suspense> ); }
方案2:用Jotai的loadable处理异步状态(无需Suspense)
如果你不想使用Suspense,可以用Jotai提供的loadable工具将异步原子转换为包含状态的同步原子,明确处理加载、成功、失败三种状态:
import { useAtomValue } from 'jotai'; import { loadable } from 'jotai/utils'; import { allPokemonAtom } from './your-atom-file'; // 将异步原子转换为可加载状态的原子 const allPokemonLoadable = loadable(allPokemonAtom); function PokemonList() { const { state, data, error } = useAtomValue(allPokemonLoadable); if (state === 'loading') return <div>加载中...</div>; if (state === 'hasError') return <div>加载失败:{error?.message}</div>; // 此时data一定是Pokemon[]类型,可安全调用filter const filteredPokemon = data.filter(pokemon => pokemon.name.includes('pika')); return ( <ul> {filteredPokemon.map(pokemon => ( <li key={pokemon.id}>{pokemon.name}</li> ))} </ul> ); }
方案3:手动类型守卫(不推荐,繁琐)
如果以上两种方案都不适用,可以在代码中添加类型守卫,确保调用filter前值不是Promise:
import { useAtomValue } from 'jotai'; import { allPokemonAtom } from './your-atom-file'; function PokemonList() { const allPokemon = useAtomValue(allPokemonAtom); // 类型守卫:判断是否为已解析的数组 if (Array.isArray(allPokemon)) { const filteredPokemon = allPokemon.filter(pokemon => pokemon.name.includes('pika')); return <ul>{filteredPokemon.map(...)}</ul>; } else { // 处理Promise pending状态,比如显示加载中 return <div>加载中...</div>; } }
内容的提问来源于stack exchange,提问作者Yukinosuke Takada
相关产品推荐
相关产品推荐

