L'un des avantages de React Query est l'accès facile aux champs de statut de la requête. Vous savez instantanément si votre requête est en cours de chargement ou si elle est erronée. Pour cela, la bibliothèque expose plusieurs indicateurs booléens, qui sont principalement dérivés de la machine d'état interne. En examinant les types, votre requête peut être dans l'un des états suivants :
- success : Votre requête a réussi et vous avez des data
- error : Votre requête n'a pas fonctionné et une error est définie
- pending : Votre requête n'a pas de données
Notez que l'indicateur isFetching ne fait pas partie de la machine d'état interne - c'est un indicateur supplémentaire qui sera vrai chaque fois qu'une requête est en cours. Vous pouvez être en état fetching et success, vous pouvez être en fetching et error - mais vous ne pouvez pas être en loading et success en même temps. La machine d'état s'en assure.
Avant la v5, pending s'appelait loading, et avant la v4, il y avait un quatrième état appelé idle.
De plus, l'indicateur isFetching est dérivé d'un fetchStatus secondaire - tout comme l'indicateur isPaused. Vous pouvez en savoir plus à ce sujet dans #13: Offline React Query.
L'exemple standard#
La plupart des exemples ressemblent à ceci :
const todos = useTodos()
if (todos.isPending) {
return 'Chargement...'
}
if (todos.error) {
return 'Une erreur est survenue : ' + todos.error.message
}
return <div>{todos.data.map(renderTodo)}</div>
Ici, nous vérifions d'abord les états pending et error, puis nous affichons nos données. Cela convient probablement à certains cas d'utilisation, mais pas à d'autres. De nombreuses solutions de récupération de données, en particulier celles créées manuellement, n'ont pas de mécanisme de rechargement, ou ne rechargent que sur des interactions explicites de l'utilisateur.
Mais React Query le fait.
Il recharge assez agressivement par défaut, et ce sans que l'utilisateur ne demande activement un rechargement. Les concepts de refetchOnMount, refetchOnWindowFocus et refetchOnReconnect sont excellents pour maintenir vos données à jour, mais ils peuvent causer une expérience utilisateur déroutante si un tel rechargement en arrière-plan échoue.
Erreurs en arrière-plan#
Dans de nombreuses situations, si un rechargement en arrière-plan échoue, il pourrait être ignoré silencieusement. Mais le code ci-dessus ne le fait pas. Regardons deux exemples :
- L'utilisateur ouvre une page, et la requête initiale se charge avec succès. Ils travaillent sur la page pendant un certain temps, puis basculent vers les onglets du navigateur pour vérifier les emails. Ils reviennent quelques minutes plus tard, et React Query fera un rechargement en arrière-plan. Maintenant, ce fetch échoue.
- Notre utilisateur est sur une page avec une vue de liste, et ils cliquent sur un élément pour descendre dans la vue de détail. Cela fonctionne bien, donc ils reviennent à la vue de liste. Une fois qu'ils reviennent à la vue de détail, ils verront les données de la mise en cache. C'est génial - sauf si le rechargement en arrière-plan échoue.
Dans les deux situations, notre requête sera dans l'état suivant :
{
"status": "error",
"error": { "message": "Something went wrong" },
"data": [{ ... }]
}
Comme vous pouvez le voir, nous aurons à la fois une erreur et les données obsolètes disponibles. C'est ce qui rend React Query génial - il embrasse le mécanisme de mise en cache stale-while-revalidate, ce qui signifie qu'il donnera toujours des données si elles existent, même si elles sont obsolètes.
Maintenant, c'est à nous de décider ce que nous devrions afficher. Est-il important de montrer l'erreur ? Est-il suffisant d'afficher uniquement les données obsolètes si nous en avons ? Devrions-nous les montrer tous, peut-être avec un petit indicateur d'erreur en arrière-plan ?
Il n'y a pas de réponse claire à cette question - cela dépend de votre cas d'utilisation exact. Cependant, étant donné les deux exemples ci-dessus, je pense que ce serait une expérience utilisateur un peu confondante si les données étaient remplacées par une écran d'erreur.
C'est encore plus pertinent lorsque nous prenons en compte que React Query réessayera trois fois par défaut les requêtes qui échouent avec un retour exponentiel, donc il pourrait prendre quelques secondes avant que les données obsolètes ne soient remplacées par l'écran d'erreur. Si vous n'avez pas non plus d'indicateur de récupération en arrière-plan, cela peut être vraiment déroutant.
C'est pourquoi je vérifie généralement d'abord la disponibilité des données :
const todos = useTodos()
if (todos.data) {
return <div>{todos.data.map(renderTodo)}</div>
}
if (todos.error) {
return 'Une erreur est survenue : ' + todos.error.message
}
return 'Chargement...'
Encore une fois, il n'y a pas de réponse claire à ce que est correct, car cela dépend beaucoup de l'utilisation. Tout le monde devrait être conscient des conséquences que a une récupération agressive, et nous devons structurer notre code en conséquence plutôt que strictement suivre les exemples simples todo 😉.
Les remerciements vont à Niek Bosch qui m'a d'abord fait remarquer pourquoi ce modèle de vérification d'état pouvait être dangereux dans certaines situations.