Search code examples
react-nativereact-state

useEffect display the good results and then display something else without any changes


import { View, Text, StyleSheet, Pressable, Button, ActivityIndicator, Alert, FlatList } from 'react-native';
import { useEffect, useState } from 'react';
import { supabase } from '../lib/supabase';
import { useAuth } from '../providers/AuthProvider';
import { Quizz } from '../types/db'
import { Stack } from 'expo-router';

export default function dailyQuizz() {
    const [listeQuestion, setListeQuestion] = useState<Quizz[]>([]);
    const { user } = useAuth();
    const [selected, setSelected] = useState('');
    const [score, setScore] = useState(0);
    const [questionEnCours, setQuestionEnCours] = useState<Quizz>();

    
    const fetchQuizz = async () => {
        console.log('Fetching....');
            
        let { data, error } = await supabase.from('questions').select('*').limit(3).returns<Quizz[]>();


        if (error) {
            Alert.alert('Error fetching data');
            console.log(error);
        }
        if(data){
            setListeQuestion(data);           
        }

    };
    useEffect(() => {
        fetchQuizz();
        setQuestionEnCours(listeQuestion[0]) ;
        console.log(listeQuestion);
    },[])

   /*const shuffleList:quizzFunction = (array) => {
       console.log('preshuffle  ' + array)
       array.sort(() => Math.random() - 0.5);
       console.log('shuffle' + array)
   }


   const shuffle = (array: []) => {
       array.sort(() => Math.random() - 0.5);
       console.log('shuffle' + array)
       return array;
   }*/


    return (
        <View>
            <Stack.Screen options={{ title: questionEnCours?.question }} />
            <Text> { questionEnCours?.question }</Text>
            {/*< FlatList
                data={questionEnCours?.reponses}
                renderItem={({ item }) => (
                    <Pressable onPress={() => setSelected(item)} key={item} style={styles.optionContainer}>
                        <Text>{item}</Text>
                    </Pressable>

                )} /> */}

        </View>

    );
}

Hello everyone !

I'am trying to build a program that can display some questions in a mobile device. My useEffect is giving some random results: when i use this code:

useEffect(() => {
        fetchQuizz();
        setQuestionEnCours(listeQuestion[0]) ;
        console.log(listeQuestion);
    },[])

it always display me an empty array

when i use this code:

useEffect(() => {
        fetchQuizz();
        setQuestionEnCours(listeQuestion[0]) ;
        console.log(listeQuestion);
    })

it gives me an infinite loop with the correct data

When i use this one

useEffect(() => {
        fetchQuizz();
        setQuestionEnCours(listeQuestion[0]) ;
        console.log(listeQuestion);
    },[questionEncours])

It gives me sometimes the correct data, sometimes an empty array without any changes from me.

During the tutorial here i already had the same issue with random answers given by my useEffect.

I might be doing something wrong here with the useEffect but the fact that sometimes i got random answer make me think that maybe my environment or something else can be the problem.

I'am new with ReactNativ so it can be a very trivial fix My english is not that good so let me know if you don't understand me

I have tried multiple things, the more relevant are the ones above


Solution

  • Let's first talk about useEffect. Essentially, it performs a simple job: it takes a function and a dependency array, and operates as follows:

    1. Without a second parameter (dependency array): The function (first parameter) is fired on every render of the component (such as when state changes or the parent component rerenders).
    2. With an empty dependency array: The function is called only on the first render.
    3. With a dependency array containing items: The function is called on the first render and whenever any dependency changes.

    Now, regarding your code, here are two approaches:

    1-Setting both states after a successful API call:

    const fetchQuizz = async () => {
        console.log('Fetching....');
        
        let { data, error } = await supabase.from('questions').select('*').limit(3).returns<Quizz[]>();
    
        if (error) {
            Alert.alert('Error fetching data');
            console.log(error);
        } else if (data) {
            setListeQuestion(data);    
            setQuestionEnCours(data[0]);
        }
    };
    
    useEffect(() => {
        fetchQuizz();
    }, []);
    

    2-Setting state in a second useEffect to ensure the data is fetched before setting the second state:

    useEffect(() => {
        // Called once on mount
        fetchQuizz();
    }, []);
    
    useEffect(() => {
        if (listeQuestion.length === 0) return;
        setQuestionEnCours(listeQuestion[0]);
        console.log(listeQuestion);
    }, [listeQuestion]);