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"}]}))