Reactjs 什么';使用React和TypeScript处理可空状态变量的最佳方法是什么?
我有以下组件,它获取文章数组,显示加载微调器,最后显示文章列表。它有一个打字错误Reactjs 什么';使用React和TypeScript处理可空状态变量的最佳方法是什么?,reactjs,typescript,Reactjs,Typescript,我有以下组件,它获取文章数组,显示加载微调器,最后显示文章列表。它有一个打字错误 const-ArticleListContainer:React.FC=()=>{ const[articles,setArticles]=useState(null) 常量[isFetched,setIsFetched]=useState(false) useffect(()=>{ fetchArticles() .然后(数据=>setArticles(数据)) .然后(()=>setIsFetched(true
const-ArticleListContainer:React.FC=()=>{
const[articles,setArticles]=useState(null)
常量[isFetched,setIsFetched]=useState(false)
useffect(()=>{
fetchArticles()
.然后(数据=>setArticles(数据))
.然后(()=>setIsFetched(true))
}, [])
return isFetched?://错误!
}
这里的问题是,articles
可以为空。ArticleList
接受的articles
道具不能为空
但是,我知道如果已经获取数据,articles
不能为空。如果我使用一个自定义钩子来获取文章,这种关系就会变得更加清晰
const-ArticleListContainer:React.FC=()=>{
const{data:articles,错误,isFetching}=useAsync(fetchArticles)
如果(正在获取){
返回
}else if(错误!==null){
返回
}
返回//错误!
}
通过设计useAsync
,如果isFetching
为false
且error
为null
,文章
不能null
以下是我想出的一些解决办法
1。检查空值
if(articles==null){
抛出新错误('Articles为null!')
}
我不应该这样做,因为除非fetchArticles
的返回值为null,否则(理论上)永远不会使用此代码
2<代码>代码>操作员
返回
放一堆可能不是个好主意代码>运算符无处不在
是否有更好的方法来编写/键入此组件?您正在尝试使用单独的useState
挂钩对状态进行建模,但是articles
和fetched
状态变量之间有着很强的相关性-没有加载之前就没有获取的项目
在这里处理所有可能的状态及其转换可能是一个好主意,在一个类似于。TypeScript可以帮助我们决定最近的状态():
//状态类型
类型状态=加载|获取|错误
类型加载={type:“加载”}
type Fetched={type:“Fetched”;articles:Article[]}
类型错误={type:“Error”,消息?:string}
常量应用=()=>{
//最初将状态设置为“已获取,无项目”
const[state,setState]=useState({type:'fetched',articles:[]})
useffect(()=>{
setState({type:“装入”})//更改为装入
fetchArticles().then(setState)//完成后更改为fetched
}, [])
返回state.type==“正在加载”?
加载…:
state.type==“错误”?
upps…:
{`fetched:${getArticleNames(state.articles)}`}
}
//只是一些助手方法/类型
类型Article={name:string}
const getArticleNames=(articles:readonly Article[])=>articles.map(a=>a.name)
const defer=(ms:number)=>新承诺((解析,拒绝)=>设置超时(()=>解析(),ms))
const fetchArticles=()=>defer(2000)。然后(
()=>({type:“fetched”,articles:[{name:“fooArticle”}]}))
如果您需要一个更大的示例,可以使用Redux进行演示。本例中没有。如果需要获取多个状态(即A
、B
和C
),我认为最好使用一些变量来指示是否仍在获取任何数据,而不是执行If(A===null | | B===null…
。此外,我从redux简化了这个示例,它似乎鼓励使用isFetched
状态。我认为发表评论的人删除了它?这是一个有效的观点;他们建议我删除isFetched
,因为我可以使用文章===null
来检查数据是否已被提取。将空数组作为回退传递如何:
Hmm…这似乎是一个相对干净的解决方案。我将尝试这样做,谢谢。您已经在跟踪提取和渲染的状态了,可以基于此将文章的初始状态设置为空数组
// State types
type State = Loading | Fetched | Error
type Loading = { type: "loading" }
type Fetched = { type: "fetched"; articles: Article[] }
type Error = {type: "error", message?: string}
const App = () => {
// initially set state to fetched with no articles
const [state, setState] = useState<State>({type: "fetched", articles: []})
useEffect(() => {
setState({type: "loading"}) // change to loading
fetchArticles().then(setState) // change to fetched, when done
}, [])
return state.type === "loading" ?
<div>loading... </div>:
state.type === "error" ?
<div>upps... </div>:
<div>{`fetched: ${getArticleNames(state.articles)}`}</div>
}
// just some helper methods/types
type Article = {name: string}
const getArticleNames = (articles: readonly Article[]) => articles.map(a => a.name)
const defer = (ms: number) => new Promise<void>((resolve, reject) => setTimeout(()=> resolve(), ms))
const fetchArticles = () => defer(2000).then<Fetched>(
()=> ({type: "fetched", articles: [{name: "fooArticle"}]}))