Issue
I'm experimenting with react-query as a replacement for my custom logic when loading data from a server in a react application.
What I cannot seem to understand is why (at least) the TypeScript typing suggests that the data
property the object returned by useQuery
can be undefined
?
If I remove the if (!query.data) {return <span>No data found</span>;}
guard in the following example, TypeScript complains that query.data
can be undefined
.
When running the example it does not seem to be undefined but (at least) the TypeScript definition assumes that it might be.
Is there any documentation that I've missed explaining why data
might be undefined?
Why does the typing suggest that data
can be undefined?
Is there a situation where data
can be undefined at runtime?
Could should not the API itself make this check and generate an error if data is really undefined?
import React from 'react';
import {useQuery} from 'react-query';
type TodoType = {
id: number,
title: string,
};
const todos: TodoType[] = [
{
id: 1,
title: 'foo',
},
{
id: 2,
title: 'bar',
},
];
const getTodos = (): Promise<TodoType[]> => new Promise(resolve => setTimeout(() => resolve(todos), 250));
export const Todos = (): JSX.Element => {
const query = useQuery('todos', getTodos);
if (query.isLoading) {
return <span>Loading...</span>;
}
if (query.isError) {
const error = query.error instanceof Error ? query.error.message : 'Error';
return <span>{error}</span>;
}
// why is this check needed?
if (!query.data) {
return <span>No data found</span>;
}
return (
<div>
<ul>
{query.data.map((todo) => (<li key={todo.id}>{todo.title}</li>))}
</ul>
</div>
);
};
Solution
why is this check needed?
because the state machine internally has 4 main states:
- loading
- error
- success
- idle
types are narrowed depending on it, but in your example, you only eliminate loading and error from the union. What remains is success or idle. If you eliminate idle as well, only success remains and the check is unnecessary.
You might want to take a look at react-query v4 though. We have removed the idle
state from the main state machine there, which would make the extra check in your example unnecessary.
Update for react-query v5
As of react-query v5, the behavior has been changed again, and the state previously called 'loading' is now called 'pending', which means you need to check for the 'error' and 'pending' states before the data can be assumed to be available and also recognized as such by TypeScript.
In v5 there's still an 'isLoading' property, but this property represents something a bit different. For more information, see the relevant section on the migration to v5 guide.
Answered By - TkDodo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.