Bonjour à tous,

J'ai suivi le tuto "Créer une application React Native" et j'ai réussi à faire une application personnalisée pour récupérer des mesures dans une base de donnée, grâce à une API
https://grafikart.fr/tutoriels/react-native-pokedex-2245#t2821

Ceci fonctionne très bien

/*(tabs)/station/[id].tsx*/
export default function Station(){

  const params = useLocalSearchParams() as {id: string};

  const {data: getstation, isFetching} = useFetchQuery("/getstation/[id]", {id: params.id})
  const measures = getstation?.stations?.[0].measures
  const station = getstation?.stations?.[0]
  [... suite ...]

Pour Info:
Premièrement je constate que lorsque charge ma station avec l'id 1, isFetching m'affiche un loader (voir l'extrait du code)

if(isFetching)
    {
      return  <RootView><Loading /></RootView>
    }
    else
    {
      return (  
        <RootView style={{paddingTop:0}}>
        [... suite ...]

Quand je charge la station avec l'ID 2, j'ai aussi un loader, mais quand je reviens sur la station 1, je n'ai plus de loader, probablement parce que les données sont chargées

Mon problème
Le problème est que les mesures sont prises toutes les 30 secondes et elles sont sauvegardées dans la base de donnée. Donc je charge une station, pour avoir les mesures en temps réel, il faudrait que ma page [id].tsx soit rechargée toutes les 60 secondes (auto-laod), pour que les dernières mesures s'affichent.

/*(tabs)/station/[id].tsx*/
export default function Station(){

  const params = useLocalSearchParams() as {id: string};

  const {data: getstation, isFetching} = useFetchQuery("/getstation/[id]", {id: params.id})
  const measures = getstation?.stations?.[0].measures
  const station = getstation?.stations?.[0]
  [... suite ...]

J'aimerais savoir comment je peux faire pour faire appel à
const {data: getstation, isFetching} = useFetchQuery("/getstation/[id]", {id: params.id}) toutes les 60 seondes pour mettre à jour mes graphiques (Gifted Charts) régulièrement

En d'autres mots, comment je peux recharger automatiquement (tabs)/station/[id].tsx, même si je dois recharger une page (station id 1) qui a déjà été chargée?

Je vous remercie pour vos suggetsions

5 réponses


Ou alors pour commencer simple, comment puis-je ajouter un bouton pour recharger ma page. On a vu que quand je passe de station id 1 à station id 2 et quand je reviens sur station id 1, cette page n'est pas chargée.
Comment pourrais-je alors créer un bouton pour forcer le chargement de cette page et donc de useFetchQuery...?

Salut !

Je comprends ton souci :
Actuellement, ta requête useFetchQuery se fait une seule fois au chargement de la page. Ce qui est normal pour useQuery.
Mais toi, tu veux rafraîchir automatiquement les données toutes les 60 secondes pour avoir les dernières mesures.

La bonne pratique pour faire ça est d’utiliser l’option refetchInterval (si ta fonction useFetchQuery est basée sur React Query ou similaire).

Voici comment tu peux modifier ton code :

export default function Station() {
const params = useLocalSearchParams() as { id: string };

const { data: getstation, isFetching } = useFetchQuery(
"/getstation/[id]",
{ id: params.id },
{
refetchInterval: 60000, // 60 000 ms = 60 secondes
}
);

const measures = getstation?.stations?.[0]?.measures;
const station = getstation?.stations?.[0];

if (isFetching) {
return (
<RootView>
<Loading />
</RootView>
);
}

return (
<RootView style={{ paddingTop: 0 }}>
{/ ... ton contenu ... /}
</RootView>
);
}

Explication :
• refetchInterval: 60000 va automatiquement rappeler ta requête API toutes les 60 secondes sans recharger la page.
• Tu verras ainsi les nouvelles mesures s’afficher toutes les minutes.
• Pas besoin de forcer un refresh manuel de la page.

Attention : Assure-toi que ta fonction useFetchQuery accepte bien les options type refetchInterval. Si elle utilise react-query sous le capot, c’est parfait.

Si tu veux de l’aide personnalisée pour intégrer cela proprement dans ton projet ou d’autres optimisations, n’hésite pas à me contacter :
Mail :excelcandidoeagle@gmail.com
Mon freelance:Zo_Redactiion

Je peux t’accompagner rapidement et efficacement !

Salut Zu_Excal,
Je préère continuer sur ce message que de correspondre par e-mail, afin que la problématique et la solution soient connues pour tous

Merci beaucoup pour ta réponse. En fait, c'est l'air simple.

export default function Station(){

  const params = useLocalSearchParams() as {id: string};
  //const params = useLocalSearchParams() as {id: string, from?: string, to?: string};
  //const {data: getstation, isFetching} = useFetchQuery("/getstation/[id]/[from]/[to]", {id: params.id, from: params.from ?? '2021-03-01', to: params.to ?? '2021-04-30'})

  const {data: getstation, isFetching} = useFetchQuery("/getstation/[id]", {id: params.id,
      refetchInterval: 60000, // 60 000 ms = 60 secondes
  })

  const measures = getstation?.stations?.[0].measures
  const station = getstation?.stations?.[0]
//  const stationId:number = station?.id_station

 useLayoutEffect(()=>{
    console.log("useLayoutEffect")
  })
  /*
  useEffect(()=>{
    console.log("USeEffect[]")
  }, [])
*/
  useEffect(()=>{
    console.log("USeEffect")
  })
  [... suite ...]

Le problème est que je n'ai pas de stations actives pour le moment, donc je ne vois pas d'effet toutes les 60 secondes.

Le useLayoutEffet() et ni le useEffect n'affiche pas le texte "uesLayoutEffect" ou useEffect dans ma console.
Y-a-t-il un moyen de vérifier que refetchInterval joue bien son rôle?

Autre question, le refetchInterval va bien mettre à jour les variables avec les dernières mesures?

const measures = getstation?.stations?.[0].measures
  const station = getstation?.stations?.[0]

Mais dans ce cas là, il faudrait faire un re-render car mes graphique ne sont pas rafraichi? non?

J'utilise TabView pour afficher mes sondes des stations par tab. Si la station a trois sondes, il y aura trois tab et dans chacune 1 graphique.

Voici des extraits de codes pour comprendre

Je loop ma variable mesures dans dataset pour prendre que ce qui m'intéresse

const dataset = new Array()     
  measures?.map((d,i) => {
    dataset.push( {
      /* For SectionList
      title: {
        title: d.datasets?.label,
        fontawesome: d.sensor_type_awe,
      },*/
      label: d.datasets?.label,
      fontawesome: d.sensor_type_awe,
      //data: [d.datasets?.data], // For SectionList
      data: d.datasets?.data,
      id_sensor: d.id_sensor,
      type: d.datasets?.type,
      borderColor   : d.datasets?.borderColor,
      backgroundColor   : d.datasets?.backgroundColor,
      showLine: d.datasets?.showLine,
      pointStyle: d.datasets?.pointStyle,
      fill: d.datasets?.fill,
      borderWidth: d.datasets?.borderWidth,
      pointRadius: d.datasets?.pointRadius,
    })
  })

J'affiche ma TabView

 <TabView
              commonOptions={{
                icon: ({ route, focused, color }) => (
                  <FontAwesome name={route.icon} size={22} color={color} />
                ),
              }}
              navigationState={{ index, routes }}
              //indicatorStyle={{ backgroundColor: 'white' }}
              style={{ flex:1, backgroundColor: 'white' }}
              renderTabBar={prop => <TabBar 
                {...prop} 
                inactiveColor={colors.grayMedium}
                activeColor={colors.greenDark}
                //renderTabBarItem={pr=>(<Text style={{color:'red'}}>{pr.labelText}</Text>)}
                indicatorStyle={{ backgroundColor: colors.greenDark}}
                style={{backgroundColor: 'white'}} // Bar container
                //tabStyle={{backgroundColor: 'white'}} // tab br

                />}
              renderScene={SceneMap(renderScene)}
              onIndexChange={setIndexTab}
            />

J'ai encore besoin de renderScene pour préparer et afficher mes tab. La dedans ce trouve mon component <Charts />
Je loop dataset (3x pour 3 sondes)

On voit que dans <Chart/>, je reprends dans datasets, des valeurs pour définir la couleur de la courbes et certains paramettre et dans d.data, il y a les données des mesures des sondes.

dataset?.map((d,i) => {
      //routes.push({key:d.id_sensor,title:d.label,icon:d.fontawesome})
      routes.push({key:d.id_sensor,icon:d.fontawesome})

      renderScene[d.id_sensor] = () => (

        <View style={{marginTop:10}}>

          <View style={{backgroundColor:'white'}}>
            <Charts pointRadius={d.pointRadius} backgroundColor={d.backgroundColor} borderColor={d.borderColor} data={d.data} />
          </View>
          <View style={{marginVertical:10}}>

            <ScrollView>
              {d.data?.map((v:any, i:any) => {
                  return (
                      <Row key={d.id_station +'-'+ i} style={styles.sectionDetailRow}>
                        <ThemedText variant="body" style={styles.sectionDetailItem}>{v.date}</ThemedText>
                        <ThemedText style={[styles.sectionDetailItem]}><FontAwesome name={'arrow-right'} size={10} color={colors.greenDark} /></ThemedText>
                        <ThemedText variant="bodyItalic" style={styles.sectionDetailItem}>{v.value}</ThemedText>
                      </Row>
                  )
                } 
              )}
            </ScrollView>

          </View>

        </View>
      )
    })

Si refetchInterval refait un useFatchQuery pour avoir la dernières valeur sauvegardée, il faudrait que mes graphiques se mettent à jour aussi.
Donc je me pose la question, si refetchInterval est suffisant. Ne faudrait-il pas donc faire un truc aussi pour rafraichir les éléments concernés de ma vue/page?

NB: Pendant tout le temps que j'ai pris pour mettre à jour ce post, ma console (CMD) n'a pas affiché de nouveau
(NOBRIDGE) LOG USeEffect, je ne peux donc pas suivre l'effet de refetchInterval

Merci beaucoup pour vos lumière :)

Je rectifie mes écris. Je me suis trompé. J'ai mis le refetchInterval: 60000, // 60 000 ms = 60 secondes dans

const {data: getstation, isFetching} = useFetchQuery("/getstation/[id]", {id: params.id})

mais en fait, le useFetchQuery est fonction qui se trouve dans un hook. J'ai donc modifié mon hook 'useFetchQuery.ts' de la sorte

export function useFetchQuery<T extends keyof API>(path: T, params?: Record<string, string | number>){
    // const localurl = endpoint + path
    const localurl = endpoint + Object.entries(params ?? {}).reduce((acc, [key, value]) => acc.replaceAll(`[${key}]`, value.toString()) as T, path)

    //console.log("localurl")
    //console.log(localurl)
    return useQuery({
        queryKey: [localurl],
        refetchIntervalInBackground: false,  
        refetchInterval: 60000, // 60 000 ms = 60 secondes
        queryFn: async () => { // Comment on reécupère les résultat
            //await wait(2);
            return fetch(localurl,{
                headers:{
                    Accept: 'application/json',
                }
            }).then((r) => r.json() as Promise<API[T]>); // Convertir le résultat (r) en json
        },
    })
}

et là, je vois bien ma page se rafraichir toutes minutes
https://www.eco-sensors.ch/temp/video.mov

Il faudrait que je puisse ajouter des mesures dans base de donnée pour voir le résultat. Je vais essayé de faire ceci rapidement en activant une station

Ceci étant dit, je n'ai pas vu de grande différence avec le refetchIntervalInBackground: true, mais je pense qu'il va interagir si l'application est en background, c'est à dire, si j'ouvre une autre application en la laissant ouverte.

Y-a-t-il quelque chose à redire / améliorer?

Par contre, je vois un autre problème.

Si je vais sur une autre vue/page, par exemple, la page Alertes ((tabs)/alertes.tsx) et je reste la dessus, 1 minute, après une minute, je vois le fond 'loading et elle réapparait. (Comme sur la vidéo pour la page (tabs)/station/[id].tsx)
Et là, ca n'a pas de sens, car c'est pas "toute l'application" qui doit réagir de la sorte, mais juste la page (tabs)/station/[id].tsx